From 5ffd65c974c56e190e573c68ec2fd95fbe9a3f22 Mon Sep 17 00:00:00 2001 From: Grant Miner Date: Wed, 1 Feb 2017 17:51:58 -0600 Subject: [PATCH] Open source release --- .editorconfig | 11 + .gitignore | 3 + .jshintrc | 7 + .vscode/launch.json | 30 + .vscode/tasks.json | 190 + README.md | 77 + config/.gitignore | 1 + config/database.js | 9 + config/faker.js | 1 + config/geocoding.js | 7 + config/listener.js | 9 + config/web.js | 17 + jsconfig.json | 6 + package.json | 114 + processes.json | 19 + public/.gitignore | 8 + public/app/datatables.css | 453 + public/app/images/ajax-loader.gif | Bin 0 -> 673 bytes public/app/images/excel-icon.png | Bin 0 -> 581 bytes public/app/images/logo1.jpg | Bin 0 -> 61573 bytes public/app/images/logo1.png | Bin 0 -> 33613 bytes public/app/images/logo2.jpg | Bin 0 -> 62287 bytes public/app/images/logo2.png | Bin 0 -> 33986 bytes public/app/images/logosmall.png | Bin 0 -> 7143 bytes public/app/images/pdf-icon.png | Bin 0 -> 500 bytes public/app/images/signal0.png | Bin 0 -> 372 bytes public/app/images/signal1.png | Bin 0 -> 414 bytes public/app/images/signal2.png | Bin 0 -> 498 bytes public/app/images/signal3.png | Bin 0 -> 506 bytes public/app/images/signal4.png | Bin 0 -> 441 bytes public/app/images/signal5.png | Bin 0 -> 370 bytes public/app/images/sort_asc.png | Bin 0 -> 160 bytes public/app/images/sort_asc_disabled.png | Bin 0 -> 148 bytes public/app/images/sort_both.png | Bin 0 -> 201 bytes public/app/images/sort_desc.png | Bin 0 -> 158 bytes public/app/images/sort_desc_disabled.png | Bin 0 -> 146 bytes public/app/images/word-icon.png | Bin 0 -> 535 bytes public/app/index.html | 45 + public/app/nprogress.css | 74 + public/app/nprogress.js | 476 + public/app/nprogress.min.js | 1 + public/app/sort_asc.png | Bin 0 -> 160 bytes public/app/sort_asc_disabled.png | Bin 0 -> 148 bytes public/app/sort_both.png | Bin 0 -> 201 bytes public/app/sort_desc.png | Bin 0 -> 158 bytes public/app/sort_desc_disabled.png | Bin 0 -> 146 bytes public/favicon.ico | 0 public/images/screen1.png | Bin 0 -> 389650 bytes public/index.html | 63 + src/.babelrc | 10 + src/client/alerts.js | 34 + src/client/appDefaultState.js | 63 + src/client/appSocketState.js | 211 + src/client/appState.js | 1027 ++ src/client/appStateReducer.js | 336 + src/client/catchhandler.js | 16 + src/client/device-new.js | 156 + src/client/devices.js | 111 + src/client/events.js | 270 + src/client/fleets.js | 226 + src/client/formatDate.js | 13 + src/client/formitem.js | 26 + src/client/getselectvalues.js | 17 + src/client/help.js | 34 + src/client/i18n.js | 237 + src/client/isUserMetric.js | 8 + src/client/keyhelper.js | 71 + src/client/locations.js | 13 + src/client/main.js | 35 + src/client/map.js | 89 + src/client/markers/OrgMarkers.js | 112 + src/client/markers/clicklistenerfactory.js | 125 + src/client/markers/markerWithLabel.js | 580 ++ src/client/markers/vehicleanimation.js | 312 + src/client/navbar.js | 324 + src/client/organization-new.js | 106 + src/client/organization.js | 205 + src/client/organizations.js | 80 + src/client/orgselector.js | 31 + src/client/reports/daily.js | 68 + src/client/reports/idle.js | 69 + src/client/reports/ignition.js | 54 + src/client/reports/jes.js | 65 + src/client/reports/mileage.js | 58 + src/client/reports/obd.js | 91 + src/client/reports/odometer.js | 45 + src/client/reports/reports.js | 305 + src/client/reports/speed.js | 78 + src/client/reports/start.js | 53 + src/client/reports/summary.js | 49 + src/client/reports/tohms.js | 32 + src/client/root.js | 227 + src/client/session.js | 158 + src/client/sidebar.js | 123 + src/client/sorts.js | 49 + src/client/style.css | 336 + src/client/style/Sorting icons.psd | Bin 0 -> 27490 bytes src/client/svg/directionsigns.js | 21 + src/client/svg/globe-placeholder.js | 13 + src/client/svg/map.js | 12 + src/client/svg/report.js | 21 + src/client/svg/truck-facing.js | 8 + src/client/svg/truck.js | 9 + src/client/svg/xcloud.js | 57 + src/client/togoogle.js | 8 + src/client/tomiles.js | 19 + src/client/tzoffset.js | 31 + src/client/user-new.js | 118 + src/client/user.js | 23 + src/client/users.js | 101 + src/client/vehicle-new.js | 110 + src/client/vehicle.js | 505 + src/client/vehicles.js | 80 + src/client/withAuth.js | 12 + src/common/addressdisplay.js | 48 + src/common/db.js | 12 + src/common/helpers.js | 481 + src/common/hidenan.js | 9 + src/common/milesfield.js | 42 + src/common/models/Device.js | 23 + src/common/models/Organization.js | 24 + src/common/models/User.js | 28 + src/common/models/Vehicle.js | 77 + src/common/report/types.js | 15 + src/common/status.js | 228 + src/common/todir.js | 20 + src/common/tohhmmss.js | 20 + src/common/tomiles.js | 12 + src/helper/datehelper.js | 24 + src/helper/eventreportparser.js | 390 + src/helper/friendlycommands.js | 74 + src/helper/reversegeo.js | 60 + src/listen/.gitignore | 1 + src/listen/decimaltohex.js | 14 + src/listen/getv.js | 13 + src/listen/listen.js | 315 + src/server/.gitignore | 1 + src/server/lib/app.js | 93 + src/server/lib/dao.js | 416 + src/server/lib/jwthelper.js | 45 + src/server/lib/password.js | 17 + src/server/lib/reports.js | 133 + src/server/lib/reports/daily.js | 67 + src/server/lib/reports/idle.js | 29 + src/server/lib/reports/ignition.js | 78 + src/server/lib/reports/jes.js | 3 + src/server/lib/reports/mileage.js | 41 + src/server/lib/reports/obd.js | 3 + src/server/lib/reports/odometer.js | 62 + src/server/lib/reports/speed.js | 3 + src/server/lib/reports/start.js | 80 + src/server/lib/reports/summary.js | 93 + src/server/lib/routes/router.js | 392 + src/server/lib/routes/vehiclehistory.js | 144 + src/server/lib/routes/vehiclestatus.js | 123 + src/server/lib/security.js | 79 + src/server/lib/sockets.js | 100 + src/server/runner.js | 17 + src/server/server.js | 106 + src/test/datehelpertest.js | 64 + src/test/decimaltohextest.js | 11 + src/test/eventreportparsertest.js | 248 + src/test/helperstest.js | 169 + src/test/jeseventparsertest.js | 53 + src/test/jestest.js | 55 + src/test/obdeventparsertest.js | 291 + src/test/osmeventparsertest.js | 118 + src/test/reports/apr3.json | 10280 +++++++++++++++++++ src/test/reports/idletest.js | 20 + src/test/reversegeotest.js | 41 + src/test/tractorobd.js | 42 + src/tools/createAnAdmin.js | 49 + src/tools/faker.js | 74 + src/tools/filter.js | 44 + src/tools/hash.js | 16 + src/tools/locgenerator.js | 79 + src/tools/redb.js | 50 + src/tools/schema.js | 50 + webpack.config.js | 129 + yarn.lock | 5703 ++++++++++ 180 files changed, 31148 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 README.md create mode 100644 config/.gitignore create mode 100644 config/database.js create mode 120000 config/faker.js create mode 100644 config/geocoding.js create mode 100644 config/listener.js create mode 100644 config/web.js create mode 100644 jsconfig.json create mode 100644 package.json create mode 100644 processes.json create mode 100644 public/.gitignore create mode 100644 public/app/datatables.css create mode 100644 public/app/images/ajax-loader.gif create mode 100644 public/app/images/excel-icon.png create mode 100644 public/app/images/logo1.jpg create mode 100644 public/app/images/logo1.png create mode 100644 public/app/images/logo2.jpg create mode 100644 public/app/images/logo2.png create mode 100644 public/app/images/logosmall.png create mode 100644 public/app/images/pdf-icon.png create mode 100644 public/app/images/signal0.png create mode 100644 public/app/images/signal1.png create mode 100644 public/app/images/signal2.png create mode 100644 public/app/images/signal3.png create mode 100644 public/app/images/signal4.png create mode 100644 public/app/images/signal5.png create mode 100644 public/app/images/sort_asc.png create mode 100644 public/app/images/sort_asc_disabled.png create mode 100644 public/app/images/sort_both.png create mode 100644 public/app/images/sort_desc.png create mode 100644 public/app/images/sort_desc_disabled.png create mode 100644 public/app/images/word-icon.png create mode 100644 public/app/index.html create mode 100644 public/app/nprogress.css create mode 100644 public/app/nprogress.js create mode 100644 public/app/nprogress.min.js create mode 100644 public/app/sort_asc.png create mode 100644 public/app/sort_asc_disabled.png create mode 100644 public/app/sort_both.png create mode 100644 public/app/sort_desc.png create mode 100644 public/app/sort_desc_disabled.png create mode 100644 public/favicon.ico create mode 100644 public/images/screen1.png create mode 100644 public/index.html create mode 100644 src/.babelrc create mode 100644 src/client/alerts.js create mode 100644 src/client/appDefaultState.js create mode 100644 src/client/appSocketState.js create mode 100644 src/client/appState.js create mode 100644 src/client/appStateReducer.js create mode 100644 src/client/catchhandler.js create mode 100644 src/client/device-new.js create mode 100644 src/client/devices.js create mode 100644 src/client/events.js create mode 100644 src/client/fleets.js create mode 100644 src/client/formatDate.js create mode 100644 src/client/formitem.js create mode 100644 src/client/getselectvalues.js create mode 100644 src/client/help.js create mode 100644 src/client/i18n.js create mode 100644 src/client/isUserMetric.js create mode 100644 src/client/keyhelper.js create mode 100644 src/client/locations.js create mode 100644 src/client/main.js create mode 100644 src/client/map.js create mode 100644 src/client/markers/OrgMarkers.js create mode 100644 src/client/markers/clicklistenerfactory.js create mode 100644 src/client/markers/markerWithLabel.js create mode 100644 src/client/markers/vehicleanimation.js create mode 100644 src/client/navbar.js create mode 100644 src/client/organization-new.js create mode 100644 src/client/organization.js create mode 100644 src/client/organizations.js create mode 100644 src/client/orgselector.js create mode 100644 src/client/reports/daily.js create mode 100644 src/client/reports/idle.js create mode 100644 src/client/reports/ignition.js create mode 100644 src/client/reports/jes.js create mode 100644 src/client/reports/mileage.js create mode 100644 src/client/reports/obd.js create mode 100644 src/client/reports/odometer.js create mode 100644 src/client/reports/reports.js create mode 100644 src/client/reports/speed.js create mode 100644 src/client/reports/start.js create mode 100644 src/client/reports/summary.js create mode 100644 src/client/reports/tohms.js create mode 100644 src/client/root.js create mode 100644 src/client/session.js create mode 100644 src/client/sidebar.js create mode 100644 src/client/sorts.js create mode 100644 src/client/style.css create mode 100644 src/client/style/Sorting icons.psd create mode 100644 src/client/svg/directionsigns.js create mode 100644 src/client/svg/globe-placeholder.js create mode 100644 src/client/svg/map.js create mode 100644 src/client/svg/report.js create mode 100644 src/client/svg/truck-facing.js create mode 100644 src/client/svg/truck.js create mode 100644 src/client/svg/xcloud.js create mode 100644 src/client/togoogle.js create mode 100644 src/client/tomiles.js create mode 100644 src/client/tzoffset.js create mode 100644 src/client/user-new.js create mode 100644 src/client/user.js create mode 100644 src/client/users.js create mode 100644 src/client/vehicle-new.js create mode 100644 src/client/vehicle.js create mode 100644 src/client/vehicles.js create mode 100644 src/client/withAuth.js create mode 100644 src/common/addressdisplay.js create mode 100644 src/common/db.js create mode 100644 src/common/helpers.js create mode 100644 src/common/hidenan.js create mode 100644 src/common/milesfield.js create mode 100644 src/common/models/Device.js create mode 100644 src/common/models/Organization.js create mode 100644 src/common/models/User.js create mode 100644 src/common/models/Vehicle.js create mode 100644 src/common/report/types.js create mode 100644 src/common/status.js create mode 100644 src/common/todir.js create mode 100644 src/common/tohhmmss.js create mode 100644 src/common/tomiles.js create mode 100755 src/helper/datehelper.js create mode 100755 src/helper/eventreportparser.js create mode 100644 src/helper/friendlycommands.js create mode 100644 src/helper/reversegeo.js create mode 100644 src/listen/.gitignore create mode 100644 src/listen/decimaltohex.js create mode 100644 src/listen/getv.js create mode 100644 src/listen/listen.js create mode 100644 src/server/.gitignore create mode 100644 src/server/lib/app.js create mode 100644 src/server/lib/dao.js create mode 100644 src/server/lib/jwthelper.js create mode 100644 src/server/lib/password.js create mode 100644 src/server/lib/reports.js create mode 100644 src/server/lib/reports/daily.js create mode 100644 src/server/lib/reports/idle.js create mode 100644 src/server/lib/reports/ignition.js create mode 100644 src/server/lib/reports/jes.js create mode 100644 src/server/lib/reports/mileage.js create mode 100644 src/server/lib/reports/obd.js create mode 100644 src/server/lib/reports/odometer.js create mode 100644 src/server/lib/reports/speed.js create mode 100644 src/server/lib/reports/start.js create mode 100644 src/server/lib/reports/summary.js create mode 100644 src/server/lib/routes/router.js create mode 100644 src/server/lib/routes/vehiclehistory.js create mode 100644 src/server/lib/routes/vehiclestatus.js create mode 100644 src/server/lib/security.js create mode 100644 src/server/lib/sockets.js create mode 100644 src/server/runner.js create mode 100644 src/server/server.js create mode 100755 src/test/datehelpertest.js create mode 100644 src/test/decimaltohextest.js create mode 100755 src/test/eventreportparsertest.js create mode 100644 src/test/helperstest.js create mode 100644 src/test/jeseventparsertest.js create mode 100644 src/test/jestest.js create mode 100644 src/test/obdeventparsertest.js create mode 100644 src/test/osmeventparsertest.js create mode 100644 src/test/reports/apr3.json create mode 100644 src/test/reports/idletest.js create mode 100644 src/test/reversegeotest.js create mode 100644 src/test/tractorobd.js create mode 100644 src/tools/createAnAdmin.js create mode 100644 src/tools/faker.js create mode 100644 src/tools/filter.js create mode 100644 src/tools/hash.js create mode 100644 src/tools/locgenerator.js create mode 100644 src/tools/redb.js create mode 100644 src/tools/schema.js create mode 100644 webpack.config.js create mode 100644 yarn.lock diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..231c3fc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = tab diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd1840a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +node_modules +npm-debug.log diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..9e0c2c3 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,7 @@ +{ + "asi": true, + "node": true, + "browser": true, + "eqnull": true, + "laxbreak": true +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..bac4b5f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "node", + "request": "launch", + "program": "app/web/server.js", + "stopOnEntry": false, + "args": [], + "cwd": "./app/web", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "externalConsole": false, + "sourceMaps": false, + "outDir": null + }, + { + "name": "Attach", + "type": "node", + "request": "attach", + "port": 5858 + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..d232911 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,190 @@ +// Available variables which can be used inside of strings. +// ${workspaceRoot}: the root folder of the team +// ${file}: the current opened file +// ${fileBasename}: the current opened file's basename +// ${fileDirname}: the current opened file's dirname +// ${fileExtname}: the current opened file's extension +// ${cwd}: the current working directory of the spawned process + +// A task runner that calls the Typescript compiler (tsc) and +// Compiles a HelloWorld.ts program +{ + "version": "0.1.0", + + // The command is tsc. Assumes that tsc has been installed using npm install -g typescript + "command": "tsc", + + // The command is a shell script + "isShellCommand": true, + + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + + // args is the HelloWorld program to compile. + "args": ["HelloWorld.ts"], + + // use the standard tsc problem matcher to find compile problems + // in the output. + "problemMatcher": "$tsc" +} + +// A task runner that calls the Typescript compiler (tsc) and +// compiles based on a tsconfig.json file that is present in +// the root of the folder open in VSCode +/* +{ + "version": "0.1.0", + + // The command is tsc. Assumes that tsc has been installed using npm install -g typescript + "command": "tsc", + + // The command is a shell script + "isShellCommand": true, + + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + + // Tell the tsc compiler to use the tsconfig.json from the open folder. + "args": ["-p", "."], + + // use the standard tsc problem matcher to find compile problems + // in the output. + "problemMatcher": "$tsc" +} +*/ + +// A task runner configuration for gulp. Gulp provides a less task +// which compiles less to css. +/* +{ + "version": "0.1.0", + "command": "gulp", + "isShellCommand": true, + "tasks": [ + { + "taskName": "less", + // Make this the default build command. + "isBuildCommand": true, + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + // Use the standard less compilation problem matcher. + "problemMatcher": "$lessCompile" + } + ] +} +*/ + +// Uncomment the following section to use jake to build a workspace +// cloned from https://github.com/Microsoft/TypeScript.git +/* +{ + "version": "0.1.0", + // Task runner is jake + "command": "jake", + // Need to be executed in shell / cmd + "isShellCommand": true, + "showOutput": "silent", + "tasks": [ + { + // TS build command is local. + "taskName": "local", + // Make this the default build command. + "isBuildCommand": true, + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + // Use the redefined Typescript output problem matcher. + "problemMatcher": [ + "$tsc" + ] + } + ] +} +*/ + +// Uncomment the section below to use msbuild and generate problems +// for csc, cpp, tsc and vb. The configuration assumes that msbuild +// is available on the path and a solution file exists in the +// workspace folder root. +/* +{ + "version": "0.1.0", + "command": "msbuild", + "args": [ + // Ask msbuild to generate full paths for file names. + "/property:GenerateFullPaths=true" + ], + "taskSelector": "/t:", + "showOutput": "silent", + "tasks": [ + { + "taskName": "build", + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + // Use the standard MS compiler pattern to detect errors, warnings + // and infos in the output. + "problemMatcher": "$msCompile" + } + ] +} +*/ + +// Uncomment the following section to use msbuild which compiles Typescript +// and less files. +/* +{ + "version": "0.1.0", + "command": "msbuild", + "args": [ + // Ask msbuild to generate full paths for file names. + "/property:GenerateFullPaths=true" + ], + "taskSelector": "/t:", + "showOutput": "silent", + "tasks": [ + { + "taskName": "build", + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + // Use the standard MS compiler pattern to detect errors, warnings + // and infos in the output. + "problemMatcher": [ + "$msCompile", + "$lessCompile" + ] + } + ] +} +*/ +// A task runner example that defines a problemMatcher inline instead of using +// a predfined one. +/* +{ + "version": "0.1.0", + "command": "tsc", + "isShellCommand": true, + "args": ["HelloWorld.ts"], + "showOutput": "silent", + "problemMatcher": { + // The problem is owned by the typescript language service. Ensure that the problems + // are merged with problems produced by Visual Studio's language service. + "owner": "typescript", + // The file name for reported problems is relative to the current working directory. + "fileLocation": ["relative", "${cwd}"], + // The actual pattern to match problems in the output. + "pattern": { + // The regular expression. Matches HelloWorld.ts(2,10): error TS2339: Property 'logg' does not exist on type 'Console'. + "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$", + // The match group that denotes the file containing the problem. + "file": 1, + // The match group that denotes the problem location. + "location": 2, + // The match group that denotes the problem's severity. Can be omitted. + "severity": 3, + // The match group that denotes the problem code. Can be omitted. + "code": 4, + // The match group that denotes the problem's message. + "message": 5 + } + } +} +*/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db8d2e --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# Agile GPS: Open Source Fleet Tracking + +## Installation Guide + +### Environment Setup +1. You need at a minimum Node.js 4.0. + +1. Install the babel-cli: ```npm i -g babel-cli``` + +1. Install RethinkDB. + +1. Start a RethinkDB instance. To start a rethinkdb instance, run the command: + +``` +rethinkdb +``` + + + +It will creates its working files in the current directory. + +1. Verify you can access the RethinkDB admin console at http://localhost:8080 + +## Project Setup + +1. In the cloned *agilegps* folder, run ```npm install``` to install the dependencies from package.json. + +2. Run ```npm run webpack```. This builds the front end based on the package.json scripts section which is using webpack. + +## Schema Setup + +1. ```cd agilegps/src/tools``` + +1. Run ```babel-node schema.js``` to create the DB, tables, and indexes. It’s safe to run this multiple times because it does not drop any DB objects. Verify that the tables exist in the RethinkDB admin console. It should only take a few seconds to run. + +1. Run ```babel-node createAnAdmin.js admin password``` to create an Admin user. + +## Building the Front End +1. ```npm run watch``` from the root of the project will run webpack in watch mode, continually rebuilding the front end as changes are made. +1. ```npm run webpack``` from the root of the project runs webpack once, to rebuild the front end a single time. + + +## Building the Back End +1. ```npm run build``` from the root of the project will run babel. The built version is used by processes.json for production usage since it uses less memory than *node-babel*. + +## Running the Application + +1. ```cd agilegps/src/server``` +1. ```node runner``` starts the web server, listening for file system code changes and automatically restarting the web server process on change, for easier development. +1. ```babel-node server``` starts the server without listening for file system changes. +1. ```babel-node debug server``` runs the server in the debugger. +2. Node 6.3.0 and later has V8 Inspector integration which allows attaching Chrome DevTools to Node.js instances for debugging and profiling: https://nodejs.org/api/debugger.html#debugger_v8_inspector_integration_for_node_js +1. You should be able to access and login to the app at http://localhost:3000 + +## Running the Message Listener + +The message listener (also known as the message gateway or just gateway) receives messages from tracker devices and inserts into the database. The message listener can be started and stopped independently of the web server. + +1. ```cd agilegps/src/listener``` +1. Run: ```babel-node listen.js``` +1. To debug, ```babel-node debug listen.js``` + +## Deploying to Production + +The *processes.json* file is pre-configured for PM2 which is a convenient way to run the app in production. PM2 can be installed to automatically run the app at system startup, log process output, etc. + +1. Put your Google Maps API key in ```config/geocoding.js``` + +1. Configure *agilegps/config/web.json* + 1. isReverseProxied - if you are behind a reverse proxy, set this to true + 1. cluster - true to use all CPUs + 1. jwtSecret - you should generate a random long string here. This string is used to sign the JWT tokens. + 1. cookieKeys - you should generate an array of two strings. These are used to sign the session cookies. The array allows you to rotate in new keys. + +1. Configure *agilegps/config/listener.js* + +1. ```pm2 start processes.json``` diff --git a/config/.gitignore b/config/.gitignore new file mode 100644 index 0000000..cfaad76 --- /dev/null +++ b/config/.gitignore @@ -0,0 +1 @@ +*.pem diff --git a/config/database.js b/config/database.js new file mode 100644 index 0000000..b27fcca --- /dev/null +++ b/config/database.js @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + "servers": [ + { "host": "localhost", "port": 28015 } + ], + "db": "agilegps", + "discovery": true +} diff --git a/config/faker.js b/config/faker.js new file mode 120000 index 0000000..60b288f --- /dev/null +++ b/config/faker.js @@ -0,0 +1 @@ +faker-local.js \ No newline at end of file diff --git a/config/geocoding.js b/config/geocoding.js new file mode 100644 index 0000000..c3f3f5c --- /dev/null +++ b/config/geocoding.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = { + GOOGLE_API_KEY: 'inserthere', + PROVIDER: "local" + // PROVIDER: "google" +} diff --git a/config/listener.js b/config/listener.js new file mode 100644 index 0000000..ba9cdd3 --- /dev/null +++ b/config/listener.js @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + "port": 33333, // listen port + "host": "0.0.0.0", // listen on host + "insertrawevents": true, // insert the raw events to the DB + "geocode": true, // reverse geocode on or off + "sack": true // send SACK on or off +} diff --git a/config/web.js b/config/web.js new file mode 100644 index 0000000..45e964c --- /dev/null +++ b/config/web.js @@ -0,0 +1,17 @@ +'use strict'; + +module.exports = { + "proxy": false, + "isReverseProxied": false, + "port": 3000, + "tlsport": 3443, + "cluster": false, + "spdy": false, + "https": false, + "jwtSecret": "seecret", + "cookieKeys": [ + "seecret1", + "seecret2" + ], + "longStackTraces": true +} diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..0438b79 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "commonjs" + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..e010531 --- /dev/null +++ b/package.json @@ -0,0 +1,114 @@ +{ + "private": "true", + "name": "fleetspotter", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "babel -d build src -s", + "watch": "webpack --watch", + "webpack": "webpack", + "test": "babel-tap src/test" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/llambda/fleetspotter.git" + }, + "author": "", + "bugs": { + "url": "https://github.com/llambda/fleetspotter/issues" + }, + "homepage": "https://github.com/llambda/fleetspotter#readme", + "dependencies": { + "babel-cli": "^6.18.0", + "babel-core": "^6.21.0", + "babel-loader": "^6.2.10", + "babel-plugin-transform-async-to-generator": "^6.16.0", + "babel-plugin-transform-async-to-module-method": "^6.16.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", + "babel-preset-es2015": "^6.18.0", + "babel-register": "^6.18.0", + "babel-tap": "^5.0.0", + "bcrypt": "^1.0.2", + "bluebird": "^3.4.7", + "bootstrap": "^3.3.7", + "bunyan": "^1.8.5", + "cookies-js": "^1.2.3", + "deep-freeze": "0.0.1", + "es6-object-assign": "^1.0.3", + "events": "^1.1.1", + "excel-export": "^0.5.1", + "inquirer": "^2.0.0", + "isomorphic-fetch": "^2.2.1", + "j2c": "^0.11.2", + "jsonwebtoken": "^7.2.1", + "kilometers-to-miles": "^1.0.3", + "koa": "2.0.0-alpha.7", + "koa-adapter": "0.0.3", + "koa-adapter-bluebird": "0.0.1", + "koa-bodyparser": "^2.3.0", + "koa-bunyan-logger": "^1.3.0", + "koa-compress": "^1.0.9", + "koa-conditional-get": "^1.0.3", + "koa-etag": "^2.1.1", + "koa-generic-session": "^1.11.4", + "koa-helmet": "^2.0.0", + "koa-jwt": "^1.2.0", + "koa-morgan": "^1.0.1", + "koa-proxy": "^0.6.0", + "koa-response-time": "^1.0.2", + "koa-router": "^7.0.1", + "koa-session": "^3.4.0", + "koa-static": "^2.0.0", + "koa-unless": "^1.0.0", + "local-reverse-geocoder": "^0.2.2", + "lodash": "^4.17.2", + "lru-cache": "^4.0.2", + "lucidlocation": "0.0.1", + "mithril": "0.2", + "mithril-modal": "0.0.1", + "moment": "^2.17.1", + "node-fetch": "^1.6.3", + "node-geocoder": "^3.15.2", + "nprogress": "^0.2.0", + "pikaday2": "^2.0.1", + "pony": "^1.0.0", + "querystring": "^0.2.0", + "raf": "^3.3.0", + "redux": "^3.6.0", + "redux-logger": "^2.7.4", + "rethink-handle-uncaught": "^1.0.0", + "rethinkdbdash": "^2.3.27", + "setimmediate": "^1.0.5", + "socket.io": "^1.7.2", + "socket.io-client": "^1.7.2", + "socketio-sticky-session": "^0.4.2", + "spdy": "^3.4.4", + "timezones.json": "^1.1.0", + "translate.js": "^0.5.0", + "validator": "4.8", + "velocity-animate": "^1.4.0", + "verror": "^1.9.0", + "windrose": "^2.0.2" + }, + "devDependencies": { + "base64-font-loader": "^0.0.4", + "css-loader": "^0.26.1", + "exports-loader": "^0.6.3", + "file-loader": "^0.9.0", + "jshint": "^2.9.4", + "jshint-loader": "^0.8.3", + "json-loader": "^0.5.4", + "less": "^2.7.1", + "less-loader": "^2.2.3", + "mithril-objectify": "3", + "node-libs-browser": "^2.0.0", + "nodemon": "^1.11.0", + "raw-loader": "^0.5.1", + "style-loader": "^0.13.1", + "svg-loader": "0.0.2", + "tape": "^4.6.3", + "url-loader": "^0.5.7", + "webpack": "2" + } +} diff --git a/processes.json b/processes.json new file mode 100644 index 0000000..f6b708e --- /dev/null +++ b/processes.json @@ -0,0 +1,19 @@ +{ + "apps": [{ + "name": "web", + "script": "server.js", + "cwd": "build/server", + "args": [], + "watch": true, + "node_args": "", + "merge_logs": true + }, { + "name": "listener", + "cwd": "build/listen", + "script": "listen.js", + "args": [], + "watch": true, + "node_args": "--nouse-idle-notification --expose-gc --max-old-space-size=8192", + "merge_logs": true + }] +} diff --git a/public/.gitignore b/public/.gitignore new file mode 100644 index 0000000..e08da4d --- /dev/null +++ b/public/.gitignore @@ -0,0 +1,8 @@ +*.woff2 +vendors.js* +bundle.js* +*.map +*.ttf +*.eot +*.svg +*.woff diff --git a/public/app/datatables.css b/public/app/datatables.css new file mode 100644 index 0000000..e29a70c --- /dev/null +++ b/public/app/datatables.css @@ -0,0 +1,453 @@ +/* + * Table styles + */ +table.dataTable { + width: 100%; + margin: 0 auto; + clear: both; + border-collapse: separate; + border-spacing: 0; + /* + * Header and footer styles + */ + /* + * Body styles + */ +} +table.dataTable thead th, +table.dataTable tfoot th { + font-weight: bold; +} +table.dataTable thead th, +table.dataTable thead td { + padding: 10px 18px; + border-bottom: 1px solid #111; +} +table.dataTable thead th:active, +table.dataTable thead td:active { + outline: none; +} +table.dataTable tfoot th, +table.dataTable tfoot td { + padding: 10px 18px 6px 18px; + border-top: 1px solid #111; +} +table.dataTable thead .sorting, +table.dataTable thead .sorting_asc, +table.dataTable thead .sorting_desc { + cursor: pointer; + *cursor: hand; +} +table.dataTable thead .sorting, +table.dataTable thead .sorting_asc, +table.dataTable thead .sorting_desc, +table.dataTable thead .sorting_asc_disabled, +table.dataTable thead .sorting_desc_disabled { + background-repeat: no-repeat; + background-position: center right; +} +table.dataTable thead .sorting { + background-image: url("../images/sort_both.png"); +} +table.dataTable thead .sorting_asc { + background-image: url("../images/sort_asc.png"); +} +table.dataTable thead .sorting_desc { + background-image: url("../images/sort_desc.png"); +} +table.dataTable thead .sorting_asc_disabled { + background-image: url("../images/sort_asc_disabled.png"); +} +table.dataTable thead .sorting_desc_disabled { + background-image: url("../images/sort_desc_disabled.png"); +} +table.dataTable tbody tr { + background-color: #ffffff; +} +table.dataTable tbody tr.selected { + background-color: #B0BED9; +} +table.dataTable tbody th, +table.dataTable tbody td { + padding: 8px 10px; +} +table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td { + border-top: 1px solid #ddd; +} +table.dataTable.row-border tbody tr:first-child th, +table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th, +table.dataTable.display tbody tr:first-child td { + border-top: none; +} +table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td { + border-top: 1px solid #ddd; + border-right: 1px solid #ddd; +} +table.dataTable.cell-border tbody tr th:first-child, +table.dataTable.cell-border tbody tr td:first-child { + border-left: 1px solid #ddd; +} +table.dataTable.cell-border tbody tr:first-child th, +table.dataTable.cell-border tbody tr:first-child td { + border-top: none; +} +table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd { + background-color: #f9f9f9; +} +table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected { + background-color: #acbad4; +} +table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover { + background-color: #f6f6f6; +} +table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected { + background-color: #aab7d1; +} +table.dataTable.order-column tbody tr > .sorting_1, +table.dataTable.order-column tbody tr > .sorting_2, +table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1, +table.dataTable.display tbody tr > .sorting_2, +table.dataTable.display tbody tr > .sorting_3 { + background-color: #fafafa; +} +table.dataTable.order-column tbody tr.selected > .sorting_1, +table.dataTable.order-column tbody tr.selected > .sorting_2, +table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1, +table.dataTable.display tbody tr.selected > .sorting_2, +table.dataTable.display tbody tr.selected > .sorting_3 { + background-color: #acbad5; +} +table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 { + background-color: #f1f1f1; +} +table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 { + background-color: #f3f3f3; +} +table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 { + background-color: whitesmoke; +} +table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 { + background-color: #a6b4cd; +} +table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 { + background-color: #a8b5cf; +} +table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 { + background-color: #a9b7d1; +} +table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 { + background-color: #fafafa; +} +table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 { + background-color: #fcfcfc; +} +table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 { + background-color: #fefefe; +} +table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 { + background-color: #acbad5; +} +table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 { + background-color: #aebcd6; +} +table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 { + background-color: #afbdd8; +} +table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 { + background-color: #eaeaea; +} +table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 { + background-color: #ececec; +} +table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 { + background-color: #efefef; +} +table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 { + background-color: #a2aec7; +} +table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 { + background-color: #a3b0c9; +} +table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 { + background-color: #a5b2cb; +} +table.dataTable.no-footer { + border-bottom: 1px solid #111; +} +table.dataTable.nowrap th, table.dataTable.nowrap td { + white-space: nowrap; +} +table.dataTable.compact thead th, +table.dataTable.compact thead td { + padding: 4px 17px 4px 4px; +} +table.dataTable.compact tfoot th, +table.dataTable.compact tfoot td { + padding: 4px; +} +table.dataTable.compact tbody th, +table.dataTable.compact tbody td { + padding: 4px; +} +table.dataTable th.dt-left, +table.dataTable td.dt-left { + text-align: left; +} +table.dataTable th.dt-center, +table.dataTable td.dt-center, +table.dataTable td.dataTables_empty { + text-align: center; +} +table.dataTable th.dt-right, +table.dataTable td.dt-right { + text-align: right; +} +table.dataTable th.dt-justify, +table.dataTable td.dt-justify { + text-align: justify; +} +table.dataTable th.dt-nowrap, +table.dataTable td.dt-nowrap { + white-space: nowrap; +} +table.dataTable thead th.dt-head-left, +table.dataTable thead td.dt-head-left, +table.dataTable tfoot th.dt-head-left, +table.dataTable tfoot td.dt-head-left { + text-align: left; +} +table.dataTable thead th.dt-head-center, +table.dataTable thead td.dt-head-center, +table.dataTable tfoot th.dt-head-center, +table.dataTable tfoot td.dt-head-center { + text-align: center; +} +table.dataTable thead th.dt-head-right, +table.dataTable thead td.dt-head-right, +table.dataTable tfoot th.dt-head-right, +table.dataTable tfoot td.dt-head-right { + text-align: right; +} +table.dataTable thead th.dt-head-justify, +table.dataTable thead td.dt-head-justify, +table.dataTable tfoot th.dt-head-justify, +table.dataTable tfoot td.dt-head-justify { + text-align: justify; +} +table.dataTable thead th.dt-head-nowrap, +table.dataTable thead td.dt-head-nowrap, +table.dataTable tfoot th.dt-head-nowrap, +table.dataTable tfoot td.dt-head-nowrap { + white-space: nowrap; +} +table.dataTable tbody th.dt-body-left, +table.dataTable tbody td.dt-body-left { + text-align: left; +} +table.dataTable tbody th.dt-body-center, +table.dataTable tbody td.dt-body-center { + text-align: center; +} +table.dataTable tbody th.dt-body-right, +table.dataTable tbody td.dt-body-right { + text-align: right; +} +table.dataTable tbody th.dt-body-justify, +table.dataTable tbody td.dt-body-justify { + text-align: justify; +} +table.dataTable tbody th.dt-body-nowrap, +table.dataTable tbody td.dt-body-nowrap { + white-space: nowrap; +} + +table.dataTable, +table.dataTable th, +table.dataTable td { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +/* + * Control feature layout + */ +.dataTables_wrapper { + position: relative; + clear: both; + *zoom: 1; + zoom: 1; +} +.dataTables_wrapper .dataTables_length { + float: left; +} +.dataTables_wrapper .dataTables_filter { + float: right; + text-align: right; +} +.dataTables_wrapper .dataTables_filter input { + margin-left: 0.5em; +} +.dataTables_wrapper .dataTables_info { + clear: both; + float: left; + padding-top: 0.755em; +} +.dataTables_wrapper .dataTables_paginate { + float: right; + text-align: right; + padding-top: 0.25em; +} +.dataTables_wrapper .dataTables_paginate .paginate_button { + box-sizing: border-box; + display: inline-block; + min-width: 1.5em; + padding: 0.5em 1em; + margin-left: 2px; + text-align: center; + text-decoration: none !important; + cursor: pointer; + *cursor: hand; + color: #333 !important; + border: 1px solid transparent; + border-radius: 2px; +} +.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover { + color: #333 !important; + border: 1px solid #979797; + background-color: white; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc)); + /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%); + /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%); + /* FF3.6+ */ + background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%); + /* IE10+ */ + background: -o-linear-gradient(top, white 0%, #dcdcdc 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, white 0%, #dcdcdc 100%); + /* W3C */ +} +.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active { + cursor: default; + color: #666 !important; + border: 1px solid transparent; + background: transparent; + box-shadow: none; +} +.dataTables_wrapper .dataTables_paginate .paginate_button:hover { + color: white !important; + border: 1px solid #111; + background-color: #585858; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111)); + /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #585858 0%, #111 100%); + /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(top, #585858 0%, #111 100%); + /* FF3.6+ */ + background: -ms-linear-gradient(top, #585858 0%, #111 100%); + /* IE10+ */ + background: -o-linear-gradient(top, #585858 0%, #111 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, #585858 0%, #111 100%); + /* W3C */ +} +.dataTables_wrapper .dataTables_paginate .paginate_button:active { + outline: none; + background-color: #2b2b2b; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c)); + /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); + /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); + /* FF3.6+ */ + background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); + /* IE10+ */ + background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%); + /* W3C */ + box-shadow: inset 0 0 3px #111; +} +.dataTables_wrapper .dataTables_paginate .ellipsis { + padding: 0 1em; +} +.dataTables_wrapper .dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 100%; + height: 40px; + margin-left: -50%; + margin-top: -25px; + padding-top: 20px; + text-align: center; + font-size: 1.2em; + background-color: white; + background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0))); + background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); + background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); + background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); + background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); + background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); +} +.dataTables_wrapper .dataTables_length, +.dataTables_wrapper .dataTables_filter, +.dataTables_wrapper .dataTables_info, +.dataTables_wrapper .dataTables_processing, +.dataTables_wrapper .dataTables_paginate { + color: #333; +} +.dataTables_wrapper .dataTables_scroll { + clear: both; +} +.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody { + *margin-top: -1px; + -webkit-overflow-scrolling: touch; +} +.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td { + vertical-align: middle; +} +.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing, +.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing { + height: 0; + overflow: hidden; + margin: 0 !important; + padding: 0 !important; +} +.dataTables_wrapper.no-footer .dataTables_scrollBody { + border-bottom: 1px solid #111; +} +.dataTables_wrapper.no-footer div.dataTables_scrollHead table, +.dataTables_wrapper.no-footer div.dataTables_scrollBody table { + border-bottom: none; +} +.dataTables_wrapper:after { + visibility: hidden; + display: block; + content: ""; + clear: both; + height: 0; +} + +@media screen and (max-width: 767px) { + .dataTables_wrapper .dataTables_info, + .dataTables_wrapper .dataTables_paginate { + float: none; + text-align: center; + } + .dataTables_wrapper .dataTables_paginate { + margin-top: 0.5em; + } +} +@media screen and (max-width: 640px) { + .dataTables_wrapper .dataTables_length, + .dataTables_wrapper .dataTables_filter { + float: none; + text-align: center; + } + .dataTables_wrapper .dataTables_filter { + margin-top: 0.5em; + } +} diff --git a/public/app/images/ajax-loader.gif b/public/app/images/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..f2a1bc0c6f545e20e631a96e8e92f9822e75d046 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nnmm28Kh24mmkF0U1e2Nli^nlO|14{3qpHl$uzQnxasi zS(2fUn3Y(Olb@KPmzkHA&!G5|g@FsGT=74*pKD04vtxj(k)8oFBTz^Oh=E26FfcG1 zbL_hF&)}42ws10s6^G;;cE1^EoUR)U5A70}d2pLv!jVIT7j&Z~EblI3x0K*v_sV|m z0W=b9G$XP(CLnYCdK49;TX=SFc-G}o=oA=|U?{1O;Nu!CwW3C5Yw7*Bi4yD$3fCnb zwK+>}QdQ9sf*QnxY>*kpE+b{_Q;sJloS71)&(@kO!}mqf@1v(v;*8Y=G9S3kY~Cw# zY=t&c z;3~JK4HxB^lY(MD+sYeQ=t%XSSW;x^1M?dTvN=W^yNcAcy`HCte31C;)5xP%b~qs> zDP&4(%TBqBNGHwnryK;BdMI$fEg xd0mc!C@j^ZpLxYv4HmnPfI0THYuv<%+6iSmMn&w3dPGDfL1|=LY008wP(boU~ literal 0 HcmV?d00001 diff --git a/public/app/images/excel-icon.png b/public/app/images/excel-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3f4775981ed1ec039922566bf6c9452712b02043 GIT binary patch literal 581 zcmV-L0=oT)P)osl=lsNp~pAGLHmZ z*WvYgNgIrq;QG03H^YBml5s)?D2~3)fYIuIK^Yu4%<@$g+c-1#VFeCc0Q7<-xye)e*@?65FWNE7+V;@ zvycmg^9-!b3?J4$f;82BP$X!Y28(ueYu=peHKe9L*#GteC#e)VJ3Fwu^cgxXK^kFX zHK+rNer;3^cE5kY@SqcVi-PpoF{ZZya41he8mcNr5TFiZ(ZP6V3~Euu*Poxz=jcLj zw*v?JzwmZ)snS8MXXPVIEd+Znl{6NhFw0!&-oiqIn7wKOnRz8K#=i^J$=tBt-=#Hi8Geylk58{4^{uN*V$;Wk` TuQ6`s00000NkvXXu0mjf^N0Lr literal 0 HcmV?d00001 diff --git a/public/app/images/logo1.jpg b/public/app/images/logo1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..014bf65b86580f9cc23318b324e58b8518bd11eb GIT binary patch literal 61573 zcmeFa2Urx%(kMJj&RI~h7*KMCB`Q%sK* z&PgOk$(cL5===JfaL@Vf`R{rD|M_j6sjaTAs;;i?nd$1D84i07M*$iQRdrPW0)YS# z;2&_fK&N`;I?4@&xsGz-6crExq!iV)2+jc5M1zCB0Bjll0**ifL>#aH5b*EEFHY_( zu8itW5rrGTkw!`!jR1sRIL;G)B0 zKq?BPqCmc%Jq4nFq+e)QU09ueO}{YwQSifPY#!7xH6DT2Oh+@jJonKx{2-4D0i2?kcd!dggpWYN4h(MG88I$SnWDE8kncFc6URm z!I5yZwHw?PBmnx}F7O}BWJkp`M=$Me0Q{yzKXFvSk({bVx9k2iWbHm z{uc_7wUe8^wf$dcR4_Ow2lsMQ$6V6ax@?0&Ibju&{3QQ{ne;je?Q_uyVgJ)p)JKiK z^pgxq65GPV|UBad*SOe;qhvPT)ZLJ1T_@$_*S)e@7<=yZHLwvg6LObJ&Ui3h;m^EaUK_vyTCX zV}~#mjt|QLkZpnh>$a!h;RvFm0PqpS$p(Pq0OatOt2=mZTmt{Vt2;n((H3O`w^Gsq zITisbTn@0k0f6F%1Hc`Cf`o*Gl!Stml!BI=jGXouH3bFrvE%gg$LQ&g(^BBlkDsH= z-$Do_IXNX2B@Go74FeSw6$2JfF&v4|{yPc|-vG2EU~``0L%0AuS_nQZD?awJ8ywiPT#j`wqj1Gd_EL`>b-5 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%0ACAPn%2~DRasY2^4Y;fOCLZ)^hWb*PoXE<8B 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 S@OK3Mj==wy2z>J|&VK>Q0JiV| literal 0 HcmV?d00001 diff --git a/public/app/images/logo1.png b/public/app/images/logo1.png new file mode 100644 index 0000000000000000000000000000000000000000..46bc1655f6be2bdda4dcdfa90c54a168e358f2a2 GIT binary patch literal 33613 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%0D35?&3%9huxfH& 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 literal 0 HcmV?d00001 diff --git a/public/app/images/logo2.png b/public/app/images/logo2.png new file mode 100644 index 0000000000000000000000000000000000000000..7625c105d410716dfc24edb02fab7258a8eb4aea GIT binary patch literal 33986 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Ξ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 E0I{FJ+5i9m literal 0 HcmV?d00001 diff --git a/public/app/images/logosmall.png b/public/app/images/logosmall.png new file mode 100644 index 0000000000000000000000000000000000000000..24c0426dd0760ec77b7697a7ef7bdbb532538289 GIT binary patch literal 7143 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 literal 0 HcmV?d00001 diff --git a/public/app/images/pdf-icon.png b/public/app/images/pdf-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7a6dcb42d0ff62fa47544d3b122e2dc998d66774 GIT binary patch literal 500 zcmVvl)`fBvPpq zMx&AF$wLCy=ytm>0=c0}l9HB4;AOjom&*aG)#;3Lxm-d`jBJkksU*W!iBc$CEJEW~ z^f_6~mytc8WYv?y;Q)O{3(mb{rq#lFI7Ft=z%F)v-CWgFot!&Kqg)0J)9v-}WSU6V zYEXVPjkv)12E-_z$D89Ipt=eLtfy1Fb~lTKaD6R5XUV6QNjmf!c(u;*?2rg6h-&E qE71%3KSt~`+5DZGcntQh00RJAd+!;_Gf~t40000SJvRfb{s zm}9o!{dR0Nn^n&FD~?&BDTlST^yR=zIhv*^UQj(Ly!WUo04XJ6jD!$KDgBfg?>)!k zk@NYCh`hGwnS~Gl==+}Q_4-jJBADH7M_t!A=UzXUW>xjK$=mG~=iEn`s`3DT8T SYMsFV0000CDc|K@bMi!SvvN4 zSDu9sh?&i16TJ8IeNS1Iq(qJ}25T)!Dc0+Ce1M2xjNx!NkmvbxfZsZdG0f-lnR5>3 z93sLvjwH|OXxo;ms@QI~066FVoJnKpD2f7r|D{P|>X=FrQ^!=&m^y9-JgVbnMP1iD zq~qonhzOU<vMEK;)W613nFq|r1u`@9M)RA_fO4Ib8JyXjnbN77_KeKvW(N|gtZm`r4)5t z-!(JFknX=S^885CHrHFMRx5V99a?LWs@(=MX3?!zc-Aj!aX94pp`6e&^Sw*#X_Q#g$S z=?)(V+=s(^-z=rXl-h2$DaJ_Gb(CdE#>6tl;G9DU!Dh3W-oRRmF^1#uNS^284F1Mp zjA6N4&O!);5U|$by=Oiaht`^^s@Uyz0E7@;y~(D+Q4|FL|Ar=;62~>&jHqqfcX3=( z_7NPzF#H$C%?6*VuPF?H=Dwi*mGkrN`z)pOE{>ZGnun61>QIjr$HVieUR?cyp*EPK zLRJDPn^6YY-RVn8KA|2;+9%16Pv2(2IHHeu?};&vGf?*>w&_ui6-u194ZWZ2bYw%- z(HAYU66jW+(-Eh;u=CJ+TxVaUBl$?MXFPwR7-J-afOGDG?Uq?)UNoYp5mH`?(-jJ> zH9|`IzP}Xha5!)}op8o;e{7_#T519|>}(u&1m0l;p*qiGaMtIKBV^_u;D okCc-6{2ad3YK4^Y&6%~9-&Q!6?{uabC;$Ke07*qoM6N<$f}IZGdjJ3c literal 0 HcmV?d00001 diff --git a/public/app/images/signal3.png b/public/app/images/signal3.png new file mode 100644 index 0000000000000000000000000000000000000000..68d98ce9a5c65b2dee0e9036a2711adbf7d77c43 GIT binary patch literal 506 zcmVrp63M2TvAH3)>Ku+Znv8spp-&NNgT%{Npc_Hy$&fQ z>-BnJt;Jf4QVL@X%XvD%j$^Vc1K=_=lL4QLuilQ9 z`Z1&YmGJZ7`@(yFrsG;o2GmbEW6{(6E{LO-$+w*R24g9aaf2u-gs3M2g1_l#o^rZp z!H-Yh7FKGUaTsH8&fN!iucN7s)7rs&CM3?$z0{c;m3@n3lKAyw-EhVXZ}LeM;74FOaV-RaR07 zaq`_~4Q<=r>|YNnUB%hSh2XKzInL>*i+f wZQAX2%i(Z92*GlB+}X`$gAf8C1WGCX0NJ0IVOF|?)Bpeg07*qoM6N<$f{?!8j{pDw literal 0 HcmV?d00001 diff --git a/public/app/images/signal4.png b/public/app/images/signal4.png new file mode 100644 index 0000000000000000000000000000000000000000..e81a5288d45dd5c07589bbb0aef2f44a09c74d75 GIT binary patch literal 441 zcmV;q0Y?6bP)@E<&QVnrNs&F&)9G}0fH8))ZHc0YIF26!yr%D7S|Ok9 zIsC+YzkH6o_lO9_7_7CA0rGi5n^x%GlqlTv&OAK=Xb&}Yq)};xQhD!8aH|eIPbk-l zujh}E)E&+`thG4j9s~T>p|j&}rLh;^1^4JE$^roI{C$8+Iz;5^Jq1JRxEgS;j$Xja z?#+Aa2hq_B(6a=SH-qTt1+-~Jvo8nH(R<0#Sh~ubvjf0ehnVB>oZ|f2o^uWnq3b%F za|HFaAlo0vlsfya_L`z7Zt68nbB^mU4B72=)OAg;S%<{&7F}q@<1qls)sj5dH}y_Y jF_}zQtyU;rPU zTUO0pY4y@=*NnbNewS)I8Xxc{$kbbP1Z@=x68ynCf5SRU=JiQEOXe*9rTXijvbpN? z?@e=#C~p^azPr#a%dcJe^_9klmoCp2S(GQ>r1!hoy8TwzmgpD0lh2-q`yC(Z6n&AXUbrBq_Xk9#h&krpMRPn)6EoYp~n8K$cOLD(-|@|P8&*9 z{Hf}@cvMAZG2_;i8!o9ll;GtlZP&c5B9pxN+p)s8I@hA+?7nNWt6}^0?N9#AIe+)* z-^j~T#HAGL_UsN?xHWE%@v#Z=-`Tq!^<3)GIn8jR_T7Xa-FvM9KiHI>&u;9gU1$sp O3I}GOXuX|8Oj3tosHiJ3*4TN zC7>_x-r1O=t(?KoTC+`+>7&2GzdqLHBg&F)2Q?&EGZ+}|Rpsc~9`m>jw35No)z4*} HQ$iB}HK{Sd literal 0 HcmV?d00001 diff --git a/public/app/images/sort_asc_disabled.png b/public/app/images/sort_asc_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..fb11dfe24a6c564cb7ddf8bc96703ebb121df1e7 GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S0wixl{&NRX(Vi}jAsXkC6BcOhI9!^3NY?Do zDX;f`c1`y6n0RgO@$!H7chZT&|Jn0dmaqO^XNm-CGtk!Ur<_=Jws3;%W$<+Mb6Mw<&;$T1GdZXL literal 0 HcmV?d00001 diff --git a/public/app/images/sort_both.png b/public/app/images/sort_both.png new file mode 100644 index 0000000000000000000000000000000000000000..af5bc7c5a10b9d6d57cb641aeec752428a07f0ca GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S0wixl{&NRX6FglULp08Bycxyy87-Q;~nRxO8@-UU*I^KVWyN+&SiMHu5xDOu|HNvwzODfTdXjhVyNu1 z#7^XbGKZ7LW3XeONb$RKLeE*WhqbYpIXPIqK@r4)v+qN8um%99%MPpS9d#7Ed7SL@Bp00i_>zopr0H-Zb Aj{pDw literal 0 HcmV?d00001 diff --git a/public/app/images/sort_desc.png b/public/app/images/sort_desc.png new file mode 100644 index 0000000000000000000000000000000000000000..0e156deb5f61d18f9e2ec5da4f6a8c94a5b4fb41 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S1|*9D%+3I*R8JSj5R22v2@yo z(czD9$NuDl3Ljm9c#_#4$vXUz=f1~&WY3aa=h!;z7fOEN>ySP9QA=6C-^Dmb&tuM= z4Z&=WZU;2WF>e%GI&mWJk^K!jrbro{W;-I>FeCfLGJl3}+Z^2)3Kw?+EoAU?^>bP0 Hl+XkKC^j|Q{b@g3TV7E(Grjn^aLC2o)_ptHrtUEoT$S@q)~)7U@V;W{6)!%@ u>N?4t-1qslpJw9!O?PJ&w0CbyQQ6eGcIw^N=k6bc1+T|=N;F0&{ILJLJvWRXxRmEd$bDc2WJ!SZeH zT?K!@{?;;*$s}Z1hDM`7G#X`|fCM^$a@u*~_xlwIe?%^q1K$`$qtVDlVgehRPbd@= z=(Pn{&HXrzzhGi)5=ZB6(CXwCZ>X4iQY;p0CN9hmsuv$HoBD7Nd&lEz2E9EB?jPc? zPUqX2%S~khvnB&1^(=P#iNmu5iWLL4_n%?VzQZ~55X@1 Z1_0L?Nd$*KtM&i@002ovPDHLkV1lk!-WC7= literal 0 HcmV?d00001 diff --git a/public/app/index.html b/public/app/index.html new file mode 100644 index 0000000..2c60c0f --- /dev/null +++ b/public/app/index.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + +

+ + + + + + + + + + + diff --git a/public/app/nprogress.css b/public/app/nprogress.css new file mode 100644 index 0000000..6752d7f --- /dev/null +++ b/public/app/nprogress.css @@ -0,0 +1,74 @@ +/* Make clicks pass-through */ +#nprogress { + pointer-events: none; +} + +#nprogress .bar { + background: #29d; + + position: fixed; + z-index: 1031; + top: 0; + left: 0; + + width: 100%; + height: 2px; +} + +/* Fancy blur effect */ +#nprogress .peg { + display: block; + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px #29d, 0 0 5px #29d; + opacity: 1.0; + + -webkit-transform: rotate(3deg) translate(0px, -4px); + -ms-transform: rotate(3deg) translate(0px, -4px); + transform: rotate(3deg) translate(0px, -4px); +} + +/* Remove these to get rid of the spinner */ +#nprogress .spinner { + display: block; + position: fixed; + z-index: 1031; + top: 15px; + right: 15px; +} + +#nprogress .spinner-icon { + width: 18px; + height: 18px; + box-sizing: border-box; + + border: solid 2px transparent; + border-top-color: #29d; + border-left-color: #29d; + border-radius: 50%; + + -webkit-animation: nprogress-spinner 400ms linear infinite; + animation: nprogress-spinner 400ms linear infinite; +} + +.nprogress-custom-parent { + overflow: hidden; + position: relative; +} + +.nprogress-custom-parent #nprogress .spinner, +.nprogress-custom-parent #nprogress .bar { + position: absolute; +} + +@-webkit-keyframes nprogress-spinner { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} +@keyframes nprogress-spinner { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + diff --git a/public/app/nprogress.js b/public/app/nprogress.js new file mode 100644 index 0000000..b23b300 --- /dev/null +++ b/public/app/nprogress.js @@ -0,0 +1,476 @@ +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +;(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.NProgress = factory(); + } + +})(this, function() { + var NProgress = {}; + + NProgress.version = '0.2.0'; + + var Settings = NProgress.settings = { + minimum: 0.08, + easing: 'ease', + positionUsing: '', + speed: 200, + trickle: true, + trickleRate: 0.02, + trickleSpeed: 800, + showSpinner: true, + barSelector: '[role="bar"]', + spinnerSelector: '[role="spinner"]', + parent: 'body', + template: '
' + }; + + /** + * Updates configuration. + * + * NProgress.configure({ + * minimum: 0.1 + * }); + */ + NProgress.configure = function(options) { + var key, value; + for (key in options) { + value = options[key]; + if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value; + } + + return this; + }; + + /** + * Last number. + */ + + NProgress.status = null; + + /** + * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`. + * + * NProgress.set(0.4); + * NProgress.set(1.0); + */ + + NProgress.set = function(n) { + var started = NProgress.isStarted(); + + n = clamp(n, Settings.minimum, 1); + NProgress.status = (n === 1 ? null : n); + + var progress = NProgress.render(!started), + bar = progress.querySelector(Settings.barSelector), + speed = Settings.speed, + ease = Settings.easing; + + progress.offsetWidth; /* Repaint */ + + queue(function(next) { + // Set positionUsing if it hasn't already been set + if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS(); + + // Add transition + css(bar, barPositionCSS(n, speed, ease)); + + if (n === 1) { + // Fade out + css(progress, { + transition: 'none', + opacity: 1 + }); + progress.offsetWidth; /* Repaint */ + + setTimeout(function() { + css(progress, { + transition: 'all ' + speed + 'ms linear', + opacity: 0 + }); + setTimeout(function() { + NProgress.remove(); + next(); + }, speed); + }, speed); + } else { + setTimeout(next, speed); + } + }); + + return this; + }; + + NProgress.isStarted = function() { + return typeof NProgress.status === 'number'; + }; + + /** + * Shows the progress bar. + * This is the same as setting the status to 0%, except that it doesn't go backwards. + * + * NProgress.start(); + * + */ + NProgress.start = function() { + if (!NProgress.status) NProgress.set(0); + + var work = function() { + setTimeout(function() { + if (!NProgress.status) return; + NProgress.trickle(); + work(); + }, Settings.trickleSpeed); + }; + + if (Settings.trickle) work(); + + return this; + }; + + /** + * Hides the progress bar. + * This is the *sort of* the same as setting the status to 100%, with the + * difference being `done()` makes some placebo effect of some realistic motion. + * + * NProgress.done(); + * + * If `true` is passed, it will show the progress bar even if its hidden. + * + * NProgress.done(true); + */ + + NProgress.done = function(force) { + if (!force && !NProgress.status) return this; + + return NProgress.inc(0.3 + 0.5 * Math.random()).set(1); + }; + + /** + * Increments by a random amount. + */ + + NProgress.inc = function(amount) { + var n = NProgress.status; + + if (!n) { + return NProgress.start(); + } else { + if (typeof amount !== 'number') { + amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95); + } + + n = clamp(n + amount, 0, 0.994); + return NProgress.set(n); + } + }; + + NProgress.trickle = function() { + return NProgress.inc(Math.random() * Settings.trickleRate); + }; + + /** + * Waits for all supplied jQuery promises and + * increases the progress as the promises resolve. + * + * @param $promise jQUery Promise + */ + (function() { + var initial = 0, current = 0; + + NProgress.promise = function($promise) { + if (!$promise || $promise.state() === "resolved") { + return this; + } + + if (current === 0) { + NProgress.start(); + } + + initial++; + current++; + + $promise.always(function() { + current--; + if (current === 0) { + initial = 0; + NProgress.done(); + } else { + NProgress.set((initial - current) / initial); + } + }); + + return this; + }; + + })(); + + /** + * (Internal) renders the progress bar markup based on the `template` + * setting. + */ + + NProgress.render = function(fromStart) { + if (NProgress.isRendered()) return document.getElementById('nprogress'); + + addClass(document.documentElement, 'nprogress-busy'); + + var progress = document.createElement('div'); + progress.id = 'nprogress'; + progress.innerHTML = Settings.template; + + var bar = progress.querySelector(Settings.barSelector), + perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0), + parent = document.querySelector(Settings.parent), + spinner; + + css(bar, { + transition: 'all 0 linear', + transform: 'translate3d(' + perc + '%,0,0)' + }); + + if (!Settings.showSpinner) { + spinner = progress.querySelector(Settings.spinnerSelector); + spinner && removeElement(spinner); + } + + if (parent != document.body) { + addClass(parent, 'nprogress-custom-parent'); + } + + parent.appendChild(progress); + return progress; + }; + + /** + * Removes the element. Opposite of render(). + */ + + NProgress.remove = function() { + removeClass(document.documentElement, 'nprogress-busy'); + removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent'); + var progress = document.getElementById('nprogress'); + progress && removeElement(progress); + }; + + /** + * Checks if the progress bar is rendered. + */ + + NProgress.isRendered = function() { + return !!document.getElementById('nprogress'); + }; + + /** + * Determine which positioning CSS rule to use. + */ + + NProgress.getPositioningCSS = function() { + // Sniff on document.body.style + var bodyStyle = document.body.style; + + // Sniff prefixes + var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' : + ('MozTransform' in bodyStyle) ? 'Moz' : + ('msTransform' in bodyStyle) ? 'ms' : + ('OTransform' in bodyStyle) ? 'O' : ''; + + if (vendorPrefix + 'Perspective' in bodyStyle) { + // Modern browsers with 3D support, e.g. Webkit, IE10 + return 'translate3d'; + } else if (vendorPrefix + 'Transform' in bodyStyle) { + // Browsers without 3D support, e.g. IE9 + return 'translate'; + } else { + // Browsers without translate() support, e.g. IE7-8 + return 'margin'; + } + }; + + /** + * Helpers + */ + + function clamp(n, min, max) { + if (n < min) return min; + if (n > max) return max; + return n; + } + + /** + * (Internal) converts a percentage (`0..1`) to a bar translateX + * percentage (`-100%..0%`). + */ + + function toBarPerc(n) { + return (-1 + n) * 100; + } + + + /** + * (Internal) returns the correct CSS for changing the bar's + * position given an n percentage, and speed and ease from Settings + */ + + function barPositionCSS(n, speed, ease) { + var barCSS; + + if (Settings.positionUsing === 'translate3d') { + barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' }; + } else if (Settings.positionUsing === 'translate') { + barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' }; + } else { + barCSS = { 'margin-left': toBarPerc(n)+'%' }; + } + + barCSS.transition = 'all '+speed+'ms '+ease; + + return barCSS; + } + + /** + * (Internal) Queues a function to be executed. + */ + + var queue = (function() { + var pending = []; + + function next() { + var fn = pending.shift(); + if (fn) { + fn(next); + } + } + + return function(fn) { + pending.push(fn); + if (pending.length == 1) next(); + }; + })(); + + /** + * (Internal) Applies css properties to an element, similar to the jQuery + * css method. + * + * While this helper does assist with vendor prefixed property names, it + * does not perform any manipulation of values prior to setting styles. + */ + + var css = (function() { + var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ], + cssProps = {}; + + function camelCase(string) { + return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) { + return letter.toUpperCase(); + }); + } + + function getVendorProp(name) { + var style = document.body.style; + if (name in style) return name; + + var i = cssPrefixes.length, + capName = name.charAt(0).toUpperCase() + name.slice(1), + vendorName; + while (i--) { + vendorName = cssPrefixes[i] + capName; + if (vendorName in style) return vendorName; + } + + return name; + } + + function getStyleProp(name) { + name = camelCase(name); + return cssProps[name] || (cssProps[name] = getVendorProp(name)); + } + + function applyCss(element, prop, value) { + prop = getStyleProp(prop); + element.style[prop] = value; + } + + return function(element, properties) { + var args = arguments, + prop, + value; + + if (args.length == 2) { + for (prop in properties) { + value = properties[prop]; + if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value); + } + } else { + applyCss(element, args[1], args[2]); + } + } + })(); + + /** + * (Internal) Determines if an element or space separated list of class names contains a class name. + */ + + function hasClass(element, name) { + var list = typeof element == 'string' ? element : classList(element); + return list.indexOf(' ' + name + ' ') >= 0; + } + + /** + * (Internal) Adds a class to an element. + */ + + function addClass(element, name) { + var oldList = classList(element), + newList = oldList + name; + + if (hasClass(oldList, name)) return; + + // Trim the opening space. + element.className = newList.substring(1); + } + + /** + * (Internal) Removes a class from an element. + */ + + function removeClass(element, name) { + var oldList = classList(element), + newList; + + if (!hasClass(element, name)) return; + + // Replace the class name. + newList = oldList.replace(' ' + name + ' ', ' '); + + // Trim the opening and closing spaces. + element.className = newList.substring(1, newList.length - 1); + } + + /** + * (Internal) Gets a space separated list of the class names on the element. + * The list is wrapped with a single space on each end to facilitate finding + * matches within the list. + */ + + function classList(element) { + return (' ' + (element.className || '') + ' ').replace(/\s+/gi, ' '); + } + + /** + * (Internal) Removes an element from the DOM. + */ + + function removeElement(element) { + element && element.parentNode && element.parentNode.removeChild(element); + } + + return NProgress; +}); + diff --git a/public/app/nprogress.min.js b/public/app/nprogress.min.js new file mode 100644 index 0000000..380d717 --- /dev/null +++ b/public/app/nprogress.min.js @@ -0,0 +1 @@ +(function(root,factory){if(typeof define==="function"&&define.amd){define(factory)}else if(typeof exports==="object"){module.exports=factory()}else{root.NProgress=factory()}})(this,function(){var NProgress={};NProgress.version="0.2.0";var Settings=NProgress.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:true,trickleRate:.02,trickleSpeed:800,showSpinner:true,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
'};NProgress.configure=function(options){var key,value;for(key in options){value=options[key];if(value!==undefined&&options.hasOwnProperty(key))Settings[key]=value}return this};NProgress.status=null;NProgress.set=function(n){var started=NProgress.isStarted();n=clamp(n,Settings.minimum,1);NProgress.status=n===1?null:n;var progress=NProgress.render(!started),bar=progress.querySelector(Settings.barSelector),speed=Settings.speed,ease=Settings.easing;progress.offsetWidth;queue(function(next){if(Settings.positionUsing==="")Settings.positionUsing=NProgress.getPositioningCSS();css(bar,barPositionCSS(n,speed,ease));if(n===1){css(progress,{transition:"none",opacity:1});progress.offsetWidth;setTimeout(function(){css(progress,{transition:"all "+speed+"ms linear",opacity:0});setTimeout(function(){NProgress.remove();next()},speed)},speed)}else{setTimeout(next,speed)}});return this};NProgress.isStarted=function(){return typeof NProgress.status==="number"};NProgress.start=function(){if(!NProgress.status)NProgress.set(0);var work=function(){setTimeout(function(){if(!NProgress.status)return;NProgress.trickle();work()},Settings.trickleSpeed)};if(Settings.trickle)work();return this};NProgress.done=function(force){if(!force&&!NProgress.status)return this;return NProgress.inc(.3+.5*Math.random()).set(1)};NProgress.inc=function(amount){var n=NProgress.status;if(!n){return NProgress.start()}else{if(typeof amount!=="number"){amount=(1-n)*clamp(Math.random()*n,.1,.95)}n=clamp(n+amount,0,.994);return NProgress.set(n)}};NProgress.trickle=function(){return NProgress.inc(Math.random()*Settings.trickleRate)};(function(){var initial=0,current=0;NProgress.promise=function($promise){if(!$promise||$promise.state()==="resolved"){return this}if(current===0){NProgress.start()}initial++;current++;$promise.always(function(){current--;if(current===0){initial=0;NProgress.done()}else{NProgress.set((initial-current)/initial)}});return this}})();NProgress.render=function(fromStart){if(NProgress.isRendered())return document.getElementById("nprogress");addClass(document.documentElement,"nprogress-busy");var progress=document.createElement("div");progress.id="nprogress";progress.innerHTML=Settings.template;var bar=progress.querySelector(Settings.barSelector),perc=fromStart?"-100":toBarPerc(NProgress.status||0),parent=document.querySelector(Settings.parent),spinner;css(bar,{transition:"all 0 linear",transform:"translate3d("+perc+"%,0,0)"});if(!Settings.showSpinner){spinner=progress.querySelector(Settings.spinnerSelector);spinner&&removeElement(spinner)}if(parent!=document.body){addClass(parent,"nprogress-custom-parent")}parent.appendChild(progress);return progress};NProgress.remove=function(){removeClass(document.documentElement,"nprogress-busy");removeClass(document.querySelector(Settings.parent),"nprogress-custom-parent");var progress=document.getElementById("nprogress");progress&&removeElement(progress)};NProgress.isRendered=function(){return!!document.getElementById("nprogress")};NProgress.getPositioningCSS=function(){var bodyStyle=document.body.style;var vendorPrefix="WebkitTransform"in bodyStyle?"Webkit":"MozTransform"in bodyStyle?"Moz":"msTransform"in bodyStyle?"ms":"OTransform"in bodyStyle?"O":"";if(vendorPrefix+"Perspective"in bodyStyle){return"translate3d"}else if(vendorPrefix+"Transform"in bodyStyle){return"translate"}else{return"margin"}};function clamp(n,min,max){if(nmax)return max;return n}function toBarPerc(n){return(-1+n)*100}function barPositionCSS(n,speed,ease){var barCSS;if(Settings.positionUsing==="translate3d"){barCSS={transform:"translate3d("+toBarPerc(n)+"%,0,0)"}}else if(Settings.positionUsing==="translate"){barCSS={transform:"translate("+toBarPerc(n)+"%,0)"}}else{barCSS={"margin-left":toBarPerc(n)+"%"}}barCSS.transition="all "+speed+"ms "+ease;return barCSS}var queue=function(){var pending=[];function next(){var fn=pending.shift();if(fn){fn(next)}}return function(fn){pending.push(fn);if(pending.length==1)next()}}();var css=function(){var cssPrefixes=["Webkit","O","Moz","ms"],cssProps={};function camelCase(string){return string.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(match,letter){return letter.toUpperCase()})}function getVendorProp(name){var style=document.body.style;if(name in style)return name;var i=cssPrefixes.length,capName=name.charAt(0).toUpperCase()+name.slice(1),vendorName;while(i--){vendorName=cssPrefixes[i]+capName;if(vendorName in style)return vendorName}return name}function getStyleProp(name){name=camelCase(name);return cssProps[name]||(cssProps[name]=getVendorProp(name))}function applyCss(element,prop,value){prop=getStyleProp(prop);element.style[prop]=value}return function(element,properties){var args=arguments,prop,value;if(args.length==2){for(prop in properties){value=properties[prop];if(value!==undefined&&properties.hasOwnProperty(prop))applyCss(element,prop,value)}}else{applyCss(element,args[1],args[2])}}}();function hasClass(element,name){var list=typeof element=="string"?element:classList(element);return list.indexOf(" "+name+" ")>=0}function addClass(element,name){var oldList=classList(element),newList=oldList+name;if(hasClass(oldList,name))return;element.className=newList.substring(1)}function removeClass(element,name){var oldList=classList(element),newList;if(!hasClass(element,name))return;newList=oldList.replace(" "+name+" "," ");element.className=newList.substring(1,newList.length-1)}function classList(element){return(" "+(element.className||"")+" ").replace(/\s+/gi," ")}function removeElement(element){element&&element.parentNode&&element.parentNode.removeChild(element)}return NProgress}); \ No newline at end of file diff --git a/public/app/sort_asc.png b/public/app/sort_asc.png new file mode 100644 index 0000000000000000000000000000000000000000..e1ba61a8055fcb18273f2468d335572204667b1f GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S1|*9D%+3I*bWaz@5R22v2@;zYta_*?F5u6Q zWR@in#&u+WgT?Hi<}D3B3}GOXuX|8Oj3tosHiJ3*4TN zC7>_x-r1O=t(?KoTC+`+>7&2GzdqLHBg&F)2Q?&EGZ+}|Rpsc~9`m>jw35No)z4*} HQ$iB}HK{Sd literal 0 HcmV?d00001 diff --git a/public/app/sort_asc_disabled.png b/public/app/sort_asc_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..fb11dfe24a6c564cb7ddf8bc96703ebb121df1e7 GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S0wixl{&NRX(Vi}jAsXkC6BcOhI9!^3NY?Do zDX;f`c1`y6n0RgO@$!H7chZT&|Jn0dmaqO^XNm-CGtk!Ur<_=Jws3;%W$<+Mb6Mw<&;$T1GdZXL literal 0 HcmV?d00001 diff --git a/public/app/sort_both.png b/public/app/sort_both.png new file mode 100644 index 0000000000000000000000000000000000000000..af5bc7c5a10b9d6d57cb641aeec752428a07f0ca GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S0wixl{&NRX6FglULp08Bycxyy87-Q;~nRxO8@-UU*I^KVWyN+&SiMHu5xDOu|HNvwzODfTdXjhVyNu1 z#7^XbGKZ7LW3XeONb$RKLeE*WhqbYpIXPIqK@r4)v+qN8um%99%MPpS9d#7Ed7SL@Bp00i_>zopr0H-Zb Aj{pDw literal 0 HcmV?d00001 diff --git a/public/app/sort_desc.png b/public/app/sort_desc.png new file mode 100644 index 0000000000000000000000000000000000000000..0e156deb5f61d18f9e2ec5da4f6a8c94a5b4fb41 GIT binary patch literal 158 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
cTgyPhLwc><)CTh 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 z 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%0ATQzX7 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 z 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.@^?fWY_tD?@0tb`k_z3XCYHvu z%$YHg&G8k{QxB3YY)|%dC77km_6AFnQs05<6Q{~NvQyb7<(b@1(IWRyKvf9=Q}}aQ z64M^rr8-(IR}@$TS?bB4OVe>Yt){S!QJsMj5KpP)q@?n4SVv4MRqpVK%B%04 zbnyx_$*)z^^%ZSg=qb-3Z4_yKduWseyQDtfK{CI+y}&XR z_Xwkb<{q=(r^N6BB71H~zN}k2^`ybs>j7sk9i4sj^eN%gwAA!FgPM4d^U=hWo@P=5 zg@LJHwCx-Fr0v~8*>OE33fmv9$&S6Ghk`FxTxK%$B<19I3Ms)dI%2J_s?&|>r9)Sm zlgkda1OE&v2&=o%LwFt#sK+4RrYy%O;gxytV^bHB4RWeiWQ$}Izh&u!^FH=x2Gmlq zn?hsfvI|igzMkxxe9=bV=viG+cvq2LpzFrlhfF`?iui&*QTi|xG=hN>bi;1F@VA}gI44QFJF!4|h66Tjj{ z2)ONqhE2zf_yD)~L|L185H27O<(`H}I4ib0LeBj|6Q=HI2WA1`*BrkmWdYa_BgfU! zOXHjPuzGjsw{g_#)Fr?7>^9#^!<49JQnO86u)KRWMM?zJef_|Y?%jB^#JOaG7ky^@9 zdNeF3PdB&4h0b=e?WN8vSRo+e<-v$dAVkho%DSv1=Y-~=&OFzOpQakl#47U=PA|U#5Qb-&EIS z`>{JvnzD;at`<;~&Y8Q5Rwh-Kr5ZpE?3wtEF_7|hwan*vDBu%V6RYYC*w1M|e^;g_ zKRqd3Eon)!-&|K=$b=3oKT5G=W{M(ygyeSxzPZqKrcZ|ly){mbS2YM^4rV_+nzu+i zKA7J$Y3bKTOaT1Hi+s1S{;(tF{c3O#1fGC;evEA=2J^U{j;6=Hb&yj>W~|<@@9SZ? zeL#kPLYRcw{HAyxJT6`sp37N3QJ?Rxjb&)v(9YcgdUGGBcdNo3zgp*u9I%`2R)}S3 zo~JzeUPn>SK0+eu<=vHCrks`n!QEvd-=u7%dy7>Id0fBlP-(WhpX-%9SI9+QPG)yB zl|bOiwrKnAZ{PY;)tc*?)Up9qn%pZ<`y;cSrZlVp_Y!zwz;-zD0xb3lVkYj`mYur9U05S7NyLVt_UX2GAY7tY;ac7?ou_Du;RnN{iRqfyJ@ia z-u>*+?GoE0l)4Rec?kG^HjFS|uD=b(eso)0PxSdYt(pE8mNEQ4I11!~7y*h|T$|k66sx zcYScbjoTb#zuAop2USwJ8F`GZuMVcKZf=yCSV=I~{tsy85Msq>{ouSVO;G=MZSZ{k z(}ukRcEM^BKlB-1lt8Y8IeY~vf|$L%^WT2KpIK_yatA1r(!6XS@RtQ}a(tei_Wk@9wfall3IFq0 zu^jpT1!w&|L8tIPBZh~j3SSuhL;ru1{}$B$cX4b63EKREre-z>gBYRF_faS?Fz^Zr zb%JAq%`Ghl2M5_59l)dciuG;vzd9|P1{Dha3sU_@FpT6jfrFy2@$fh=%&P$r|8+^| z%D(#LOT`DGrWnlUU!Y9kWI?Bdv42kv?(B`G_Q2s;J0U+Acw?XM0$1tqqEo>}2pj?e z?lC&_|J;}czT0SW0)Hn#x!fBgM|;7Td#1c2#z6ri4eo;7UA`cJ6SNaY6ejVnh#5NX zZM1q^ricT?f{heN5#GZHnsDIfILtv5@OcP<12eFztINS3IEO&^?~L#Y3ztmz*Sq)c z!v&r8;OK6X0oHTpCyNE!Z{KEq#`^xZ_`Z}fM~(Ke^^ + + + + + + + + + + + + + + + + +
+ +
+
+
+
+
+ +
+
+ +
+
+
+

Get Started!

+
    +
  1. Queclink GV300 or GV500 vehicle GPS tracker
  2. +
+
+
+

Features

+
    +
  • Web interface with responsive design supports desktop and mobile browsers.
  • +
  • Real-time updates appear as soon as they come in!
  • +
  • Unlimited fleets
  • +
  • Reports: start stop, ignition, idling, mileage by state, odometer by state, speed, daily report, vehicle summary, and OBD-II.
  • +
  • GV500 OBD support. Malfunction codes, fuel level (certain vehicles), engine coolant temperature, RPMs.
  • +
  • UDP minimized mobile data usage.
  • +
  • Metric and imperial units.
  • + +
+
+
+ +
+ +
+ +
Copyright 2017 NoContractTrack.com
+ +
+ + + diff --git a/src/.babelrc b/src/.babelrc new file mode 100644 index 0000000..54d988e --- /dev/null +++ b/src/.babelrc @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["transform-es2015-modules-commonjs"], + ["transform-async-to-module-method", { + "module": "bluebird", + "method": "coroutine" + }], + "mithril-objectify" + ] +} diff --git a/src/client/alerts.js b/src/client/alerts.js new file mode 100644 index 0000000..57948cb --- /dev/null +++ b/src/client/alerts.js @@ -0,0 +1,34 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const m = require('mithril'); +const alertTypes = ['Location Enter', 'Location Exit', 'Speed Alert']; + +module.exports.controller = function(args, extras) { + const ctrl = this; + ctrl.selectedAlert = m.prop(); +}; + +module.exports.view = function(ctrl, args, extras) { + return m('div', [ + m('.col-sm-1'), + m('.col-sm-10', [ + m('.col-sm-4', m('.business-table', [ + m('h4', 'Alert Types'), + m('ul.list-group', [ + alertTypes.map(function(alert) { + return m('li.pointer list-group-item', { + class: ctrl.selectedAlert() === alert ? 'active' : '', + onclick: function() { + ctrl.selectedAlert(alert); + } + }, alert) + }) + ]), + ])), + m('.col-sm-8', m('.business-table', [ + m('h4', ctrl.selectedAlert()) + ])), + ]), + m('.col-sm-1') + ]) +}; diff --git a/src/client/appDefaultState.js b/src/client/appDefaultState.js new file mode 100644 index 0000000..229cafc --- /dev/null +++ b/src/client/appDefaultState.js @@ -0,0 +1,63 @@ +'use strict'; +import deepFreeze from 'deep-freeze'; +import {hasLang} from './i18n'; + +const defaults = { + lang: '', // set below + + user: {}, + + fleetsByID: {}, // only for the select org + + selectedAllFleets: false, + selectedFleets: [], + selectedVehicles: [], + selectedVehicle: null, + selectedVehicleHistory: [], + selectedOrg: {}, + + impliedSelectedVehicles: [], + + usersByID: {}, // username is the ID + devicesByID: {}, + orgsByID: {}, + vehiclesByID: {}, + + lastUpdated: new Date(), + + selectedItem: null, + + view: 'SESSION', + subview: '', + viewID: '', // object ID to view, if any + + startDate: new Date(), + endDate: new Date(), + + // events / errors / rawevents + eventCount: 0, + events: [], + rawevents: [], + exceptions: [], + page: 1, + pagesize: 300, + search: '', + + // view state + autoUpdate: true, + realTimeUpdates: false, // is the socket.io connection is working + showLatLong: false, + verbose: false + +}; + +if (navigator.languages) { + for (let lang of navigator.languages) { + if (hasLang(lang)) { + defaults.lang = lang; + break; + } + } +} + +module.exports = deepFreeze(defaults); diff --git a/src/client/appSocketState.js b/src/client/appSocketState.js new file mode 100644 index 0000000..2847813 --- /dev/null +++ b/src/client/appSocketState.js @@ -0,0 +1,211 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +/** +Uses Redux ( https://github.com/reactjs/redux ) to handle and keep all application state in one place. +*/ +const m = require('mithril'); +const redux = require('redux'); +const withAuth = require('./withAuth'); +const _ = require('lodash'); +const io = require('socket.io-client') +const helpers = require('../common/helpers'); +const Cookies = require('cookies-js'); +const moment = require('moment'); +const createLogger = require('redux-logger'); +const appState = require('./appState'); + +/* +Socket.io +*/ +let lastJwt; +let socket; +function handleChange(msg) { + msg = JSON.parse(msg); + + if (msg.new_val) { + // console.log(msg.new_val); + + /* new_val is like + a: 147 + bp: 1 + cmd: "FRI" + d: "2016-02-29T04:02:28.000Z" + g: 11 + h: "FAKE:00:00" + id: "20160228220228|1|0015" + ig: true + la: 18.08073 + lo: 61.51553 + m: 0 + mo: true + p: "14055" + rid: "1" + rty: "0" + s: 69 + v: "14055" + vid: "agen1" + */ + let state = appState.getState(); + + let event = _.cloneDeep(state.vehiclesByID[msg.new_val.vid]); + + if (event != null) { + event.last = msg.new_val; + + // Refer to module.exports.getAllVehicleStatus in dao.js + // 'event' is really the vehicle object with .last property containing the last status. + // Ideally get rid of the .last and just make it the status itself. + + appState.getStore().dispatch({ + type: 'CHANGED_VEHICLE_HISTORY', + event: event + }); + } + } +} + +appState.getStore().subscribe(function () { + + let state = appState.getState(); + let jwt = Cookies.get('jwt'); + + if (lastJwt !== jwt) { + lastJwt = jwt; + if (socket) { + console.log('Disconnecting socket.'); + socket.disconnect(); + } + + if (!state.user.username) { + return; + } + + socket = io(); + socket.on('connect', function () { + console.log('Socket connected.'); + appState.getStore().dispatch({ + type: 'SOCKET_CONNECT' + }); + }); + socket.on('disconnect', function (e) { + console.error(e); + appState.getStore().dispatch({ + type: 'SOCKET_DISCONNECT' + }); + }); + socket.on('error', function (e) { + console.error(e); + appState.getStore().dispatch({ + type: 'SOCKET_DISCONNECT' + }); + }); + socket.on('reconnect', function () { + console.log('Socket reconnect.'); + appState.getStore().dispatch({ + type: 'SOCKET_CONNECT' + }); + }); + + socket.on('vehiclehistory', Promise.method(handleChange)); + let tables = ['users', 'devices', 'vehicles', 'errors']; + tables.forEach(function (table) { + socket.on(table, function (ev) { + console.log(ev); + }) + }) + + socket.on('organizations', function (ev) { + ev = JSON.parse(ev); + + if (ev.new_val == null) { + appState.getStore().dispatch({ + type: 'DELETE_ORG', + org: ev.old_val + }); + } else { + appState.getStore().dispatch({ + type: 'SAVE_ORG', + org: ev.new_val + }); + } + }); + + socket.on('users', function (ev) { + ev = JSON.parse(ev); + + if (ev.new_val == null) { + appState.getStore().dispatch({ + type: 'DELETE_USER', + user: ev.old_val + }); + } else { + appState.getStore().dispatch({ + type: 'SAVE_USER', + user: ev.new_val + }); + } + }); + + socket.on('devices', function (ev) { + ev = JSON.parse(ev); + + if (ev.new_val == null) { + appState.getStore().dispatch({ + type: 'DELETE_DEVICE', + device: ev.old_val + }); + } else { + appState.getStore().dispatch({ + type: 'SAVE_DEVICE', + device: ev.new_val + }); + } + }); + + socket.on('vehicles', function (ev) { + ev = JSON.parse(ev); + + if (ev.new_val == null) { + appState.getStore().dispatch({ + type: 'DELETE_VEHICLE', + vehicle: ev.old_val + }); + } else { + appState.getStore().dispatch({ + type: 'SAVE_VEHICLE', + vehicle: ev.new_val + }); + } + }); + + socket.on('fleets', function (ev) { + let state = appState.getStore().getState(); + ev = JSON.parse(ev); + + if (ev.new_val == null) { + if (ev.old_val.orgid === state.selectedOrg.id) { + appState.getStore().dispatch({ + type: 'DELETE_FLEET', + fleet: ev.old_val + }); + } + } else { + if (ev.new_val.orgid === state.selectedOrg.id) { + appState.getStore().dispatch({ + type: 'SAVE_FLEET', + fleet: ev.new_val + }); + } + } + }); + + socket.on('errors', function (ev) { + ev = JSON.parse(ev); + + if (ev.old_val == null) { + // window.alert(JSON.stringify(ev.new_val)); + console.error(JSON.stringify(ev.new_val)); + } + }) + } +}); diff --git a/src/client/appState.js b/src/client/appState.js new file mode 100644 index 0000000..acafcb8 --- /dev/null +++ b/src/client/appState.js @@ -0,0 +1,1027 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +/** +Uses Redux ( https://github.com/reactjs/redux ) to handle and keep all application state in one place. +*/ +const m = require('mithril'); +const redux = require('redux'); +const withAuth = require('./withAuth'); +const _ = require('lodash'); +const io = require('socket.io-client') +const helpers = require('../common/helpers'); +const Cookies = require('cookies-js'); +const moment = require('moment'); +const createLogger = require('redux-logger'); +const reducer = require('./appStateReducer'); + +const REDUX_LOGGING = false +const logger = createLogger({ + duration: true, + timestamp: true +}); +const store = redux.createStore(reducer, REDUX_LOGGING ? redux.applyMiddleware(logger) : null); + +if (Cookies.get('jwt')) { + setImmediate(function () { + login(); + }); +} + +// START routing +let lastViewState = {}; +store.subscribe(function () { + let state = store.getState(); + let viewState = {}; + viewState.view = state.view; + viewState.subview = state.subview; + viewState.viewID = state.viewID; + + if (!_.isEqual(lastViewState, viewState)) { + lastViewState = viewState; + window.history.pushState(viewState, viewState.view + ' ' + viewState.subview + ' ' + viewState.viewID, '?' + JSON.stringify(viewState)); + } + // + if (['EDIT', 'RAWEVENTS', 'EVENTS', 'EXCEPTIONS'].indexOf(state.subview) < 0) { // don't redraw certain views + console.log('redrawing'); + m.redraw(); + } +}); + +window.onpopstate = function (ev) { + let location = ev.state; + store.dispatch({ + type: 'VIEW', + view: location.view, + subview: location.subview, + viewID: location.viewID + }) +} +// END routing + + +function auth() { + return { + 'headers': { + 'authorization': 'Bearer ' + Cookies.get('jwt'), + 'content-type': 'application/json; charset=UTF-8' + }, + // 'credentials': 'include' // include JWT cookie + }; +} + +function authWithCookies() { + return { + 'headers': { + 'authorization': 'Bearer ' + Cookies.get('jwt'), + 'content-type': 'application/json; charset=UTF-8' + }, + 'credentials': 'include' // include JWT cookie + }; +} + +function authJson() { + return { + 'headers': { + 'authorization': 'Bearer ' + Cookies.get('jwt'), + 'content-type': 'application/json; charset=UTF-8' + } + } +} + +function put(obj) { + return Object.assign({}, authJson(), { + method: 'PUT', + body: JSON.stringify(obj) + }); +} + +function post(obj) { + return Object.assign({}, authJson(), { + method: 'POST', + body: JSON.stringify(obj) + }); +} + +function postWithCookies(obj) { + return Object.assign({}, authWithCookies(), { + method: 'POST', + body: JSON.stringify(obj) + }); +} + +function validateResponse (response) { + if (response.ok) { + return response.json(); + } else { + NProgress.done(); + return response.json() + .then(function (json) { + let error = new Error(); + error.message = json.message + throw error; + }) + } +} + +function loadOrgState(orgid) { + NProgress.inc(); + + return Promise.resolve(fetch('/api/organizations/' + orgid, auth())) + .then(function (response) { + return validateResponse(response); + }) + .then(function (org) { + NProgress.inc(); + + store.dispatch({ + type: 'GET_ORG', + org: org + }); + + NProgress.inc(); + + let fleetp = Promise.resolve(fetch('/api/organizations/' + orgid + '/fleets', auth())) + .then(function (response) { + return validateResponse(response); + }) + .then(function (fleets) { + NProgress.inc(); + + store.dispatch({ + type: 'FLEETS', + fleets: fleets + }); + }) + + // LOAD vehicle status + let statusp = loadVehicles(orgid); + + // org users + let usersp = Promise.resolve(fetch('/api/organizations/' + orgid + '/users', auth())) + .then(function (response) { + return validateResponse(response); + }) + .then(function (users) { + NProgress.inc(); + + store.dispatch({ + type: 'ORG_USERS', + orgid: orgid, + users: users + }); + }) + return Promise.all([fleetp, statusp, usersp]); + }); +} + +function loadVehicles(orgid) { + NProgress.start(); + return Promise.resolve(fetch('/api/organizations/' + orgid + '/vehiclestatus', auth())) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (vehicles) { + store.dispatch({ + type: 'VEHICLES', + vehicles: vehicles, + orgid: orgid + }); + }) + .finally(function () { + NProgress.done(); + }) +} + +function fetchOrganizations() { + NProgress.inc(); + return Promise.resolve(fetch('/api/organizations/', auth())) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (orgs) { + store.dispatch({ + type: 'ORGS', + orgs: orgs, + }); + }) + .finally(function () { + NProgress.done(); + }) +} + +function loadSiteAdminData() { + // ALL ORGS + let orgsp = fetchOrganizations(); + + // LOAD USERS + let usersp = Promise.resolve(fetch('/api/users/', auth())) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (users) { + NProgress.inc(); + store.dispatch({ + type: 'USERS', + users: users + }); + }) + + // LOAD devices + let devicesp = fetch('/api/devices/', auth()) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (devices) { + NProgress.inc(); + store.dispatch({ + type: 'DEVICES', + devices: devices + }); + }) + + // LOAD all vehicles (needed for device <-> vehicle association) + let vehiclesp = Promise.resolve(fetch('/api/vehicles/', auth())) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (vehicles) { + NProgress.inc(); + store.dispatch({ + type: 'VEHICLES', + vehicles: vehicles + }); + }) + + return Promise.all([orgsp, usersp, devicesp, vehiclesp]) + .then(function () { + NProgress.inc(); + }); +} + +function afterLogin() { + +} + +function viewLogin() { + store.dispatch({ + type: 'VIEW', + view: 'SESSION' + }); +} +module.exports.viewLogin = viewLogin; + +function login (data) { // data is an object {username, password} + NProgress.inc(); + let initial; + if (data) { + initial = Promise.resolve(fetch('/api/session/', postWithCookies(data))) + } else { + initial = Promise.resolve(fetch('/api/session/', { + headers: { + 'authorization': 'Bearer ' + Cookies.get('jwt'), + 'content-type': 'application/json; charset=UTF-8' + } + })) + } + + return initial.then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (response) { + const user = response.user; + NProgress.inc(); + store.dispatch({ + type: 'SESSION', + user: user + }); + + let next; + if (user.isAdmin) { + next = loadSiteAdminData(); + } else { + next = fetchOrganizations(); + } + + if (store.getState().subview === 'ORG' && store.getState().viewID) { + next = next.then(function () { + return selectOrgByID(store.getState().viewID); + }) + } else if (store.getState().view === 'ORG' && store.getState().viewID) { + next = next.then(function () { + return selectOrgByID(store.getState().viewID); + }) + } else if (store.getState().user.isAdmin) { + // do nothing + } else if (store.getState().user.orgid != null) { + next = next.then(function () { + return selectOrgByID(store.getState().user.orgid); + }) + } + + next.finally(function () { + NProgress.done(); + }) + + return next; + }); +} +module.exports.login = login; + +module.exports.logOut = function() { + return Promise.resolve(fetch('/api/session', Object.assign({ + method: 'DELETE' + }, authWithCookies()))) + .then(function(response) { + Cookies.expire('jwt'); + store.dispatch({ + type: 'LOGOUT' + }); + return viewLogin(); + }) +}; + +module.exports.getState = function () { + return store.getState(); +} + +module.exports.getStore = function () { + return store; +} + +module.exports.getOrgName = function (id) { + let org = store.getState().orgsByID[id]; + return org ? org.name : ''; +} + + +function selectFleetAll() { + store.dispatch({ + type: 'SELECT_FLEET_ALL', + }); + + return Promise.resolve(); +} +module.exports.selectFleetAll = selectFleetAll; + +function selectOrgByID (orgid) { + if (!orgid) { + throw new Error('null orgid'); + } + NProgress.inc(); + + let org = store.getState().orgsByID[orgid]; + store.dispatch({ + type: 'SELECT_ORG', + org: org + }); + + return loadOrgState(orgid) + .then(function () { + return selectFleetAll(); + }) + .finally(function () { + NProgress.done(); + }) +} +module.exports.selectOrgByID = selectOrgByID; + +module.exports.deleteOrg = function (org) { + + return Promise.resolve(fetch('/api/organizations/' + org.id, Object.assign(auth(), { + method: 'DELETE' + }))) + .then(function (response) { + return validateResponse(response) + }) + .then(function () { + store.dispatch({ + type: 'DELETE_ORG', + org: org + }); + }) +} + +module.exports.deleteUser = function (user) { + let url; + if (user.orgid) { + url = '/api/organizations/' + user.orgid + '/users/' + user.username; + } else { + url = '/api/users/' + user.username; + } + + return Promise.resolve(fetch(url, Object.assign(auth(), { + method: 'DELETE' + }))) + .then(function (response) { + return validateResponse(response) + }) + .then(function () { + store.dispatch({ + type: 'DELETE_USER', + user: user + }); + }) +} + +module.exports.deleteDevice = function (device) { + return Promise.resolve(fetch('/api/devices/' + device.imei, Object.assign({ + method: 'DELETE' + }, auth()))) + .then(function (response) { + return validateResponse(response) + }) + .then(function () { + store.dispatch({ + type: 'DELETE_DEVICE', + device: device + }); + }) +} + +module.exports.deleteVehicle = function (vehicle) { + let url; + if (vehicle.orgid) { + url = '/api/organizations/' + vehicle.orgid + '/vehicles/' + vehicle.id; + } else { + url = '/api/vehicles/' + vehicle.id; + } + + return Promise.resolve(fetch(url, Object.assign({ + method: 'DELETE' + }, auth()))) + .then(function (response) { + return validateResponse(response) + }) + .then(function () { + store.dispatch({ + type: 'DELETE_VEHICLE', + vehicle: vehicle + }); + }) +} + +module.exports.saveFleet = function (fleet) { + NProgress.start(); + + if (fleet.id) { + return Promise.resolve(fetch('/api/organizations/' + fleet.orgid + '/fleets/' + fleet.id, put(fleet))) + .then(function (response) { + NProgress.inc(); + return validateResponse(response) + }) + .then(function (fleet) { + store.dispatch({ + type: 'SAVE_FLEET', + fleet: fleet + }); + }) + .finally(function () { + NProgress.done(); + }) + } else { + delete fleet.id; + + return Promise.resolve(fetch('/api/organizations/' + fleet.orgid + '/fleets/', post(fleet))) + .then(function (response) { + NProgress.inc(); + return validateResponse(response) + }) + .then(function (fleet) { + store.dispatch({ + type: 'SAVE_FLEET', + fleet: fleet + }); + }) + .finally(function () { + NProgress.done(); + }) + } +} + +module.exports.deleteFleet = function (fleet) { + NProgress.start(); + + let url; + if (fleet.orgid) { + url = '/api/organizations/' + fleet.orgid + '/fleets/' + fleet.id; + } else { + url = '/api/fleet/' + fleet.id; + } + + return Promise.resolve(fetch(url, Object.assign({ + method: 'DELETE' + }, auth()))) + .then(function (response) { + if (response.ok) { + store.dispatch({ + type: 'DELETE_FLEET', + fleet: fleet + }); + } + + return response; + }) + .finally(function () { + NProgress.done(); + }) +} + +module.exports.selectFleet = function (fleet) { + store.dispatch({ + type: 'SELECT_FLEET', + fleet: fleet + }); +} + +function updateSelectedVehicleHistory() { + NProgress.start(); + let state = store.getState(); + let vehicle = state.selectedVehicle; + + let url = '/api/organizations/' + vehicle.orgid + '/vehiclehistory/' + vehicle.id + + '?startDate=' + encodeURIComponent(state.startDate.toISOString()) + + '&endDate=' + encodeURIComponent(state.endDate.toISOString()); + + return Promise.resolve(fetch(url, auth())) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function(history) { + store.dispatch({ + type: 'VEHICLE_HISTORY', + vehicle: vehicle, + history: history + }); + }) + .finally(function () { + NProgress.done(); + }) +} + +function update() { + let state = store.getState(); + + if (state.selectedVehicle) { + return updateSelectedVehicleHistory(); + } else { + return loadVehicles(state.selectedOrg.id); + } +} +module.exports.update = update; + +module.exports.selectVehicleByID = function (id) { + let state = store.getState(); + + store.dispatch({ + type: 'SELECT_VEHICLE', + id: id + }); + + let lastStatus; + if (state.vehiclesByID[id]) { + lastStatus = state.vehiclesByID[id].last; + } + + if (lastStatus != null && lastStatus.d) { + return selectDay(moment(lastStatus.d).startOf('day').toDate()); + } +} + +module.exports.saveOrg = function(org) { + NProgress.start(); + + if (org.id) { + return Promise.resolve(fetch('/api/organizations/' + org.id, put(org))) + .then(function (response) { + NProgress.inc(); + return validateResponse(response) + }) + .then(function (org) { + store.dispatch({ + type: 'SAVE_ORG', + org: org + }); + }) + .finally(function () { + NProgress.done(); + }) + } else { + delete org.id; + + return Promise.resolve(fetch('/api/organizations/', post(org))) + .then(function (response) { + NProgress.inc(); + return validateResponse(response) + }) + .then(function (org) { + store.dispatch({ + type: 'SAVE_ORG', + org: org + }); + }) + .finally(function () { + NProgress.done(); + }) + } +} +module.exports.saveUser = function(user) { + NProgress.start(); + return Promise.resolve(fetch('/api/users/' + user.username, put(user))) + .then(function (response) { + NProgress.inc(); + return validateResponse(response) + }) + .then(function (org) { + store.dispatch({ + type: 'SAVE_USER', + user: user + }); + }) + .finally(function () { + NProgress.done(); + }) +} + +module.exports.putVehicle = function(vehicle) { + NProgress.start(); + return Promise.resolve(fetch('/api/organizations/' + vehicle.orgid + '/vehicles/' + vehicle.id, put(vehicle))) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (vehicle) { + store.dispatch({ + type: 'SAVE_VEHICLE', + vehicle: vehicle + }); + }) + .finally(function () { + NProgress.done(); + }) +} + +module.exports.postVehicle = function(vehicle) { + NProgress.start(); + delete vehicle.id; + + return Promise.resolve(fetch('/api/organizations/' + vehicle.orgid + '/vehicles/', post(vehicle))) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (vehicle) { + store.dispatch({ + type: 'SAVE_VEHICLE', + vehicle: vehicle + }); + }) + .finally(function () { + NProgress.done(); + }) +} + +module.exports.saveDevice = function(device) { + NProgress.start(); + return Promise.resolve(fetch('/api/devices/' + device.imei, put(device))) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (device) { + store.dispatch({ + type: 'SAVE_DEVICE', + device: device + }); + }) + .finally(function () { + NProgress.done(); + }) +} + +module.exports.clickItem = function (item) { + store.dispatch({ + type: 'SELECT_ITEM', + item: item + }); +} + +module.exports.selectDays = function (startDate, endDate) { + store.dispatch({ + type: 'SELECT_DAYS', + startDate: startDate, + endDate: endDate + }); + + return updateSelectedVehicleHistory(); +} + +function selectDay (startDate) { + startDate = new Date(startDate) + store.dispatch({ + type: 'SELECT_DAYS', + startDate: startDate, + endDate: moment(startDate).add(1, 'days').toDate() + }); + + return updateSelectedVehicleHistory(); +} +module.exports.selectDay = selectDay; + +function updateEvents () { + NProgress.start(); + + let state = store.getState(); + let type = _.lowerCase(state.view); + NProgress.start(); + + return Promise.resolve(fetch('/api/count/' + type + (type === 'rawevents' ? '?search=' + encodeURIComponent(state.search) : ''), auth())) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (result) { + NProgress.inc(); + store.dispatch({ + type: 'EVENT_COUNT', + count: result.count + }); + }) + .then(function () { + let url = '/api/' + type + '/?page=' + state.page + '&pagesize=' + state.pagesize + '&search=' + encodeURIComponent(state.search) + return Promise.resolve(fetch(url, auth())) + }) + .then(function (response) { + NProgress.inc(); + return validateResponse(response); + }) + .then(function (events) { + store.dispatch({ + type: 'EVENTS', + events: events + }); + }) + .finally(function () { + NProgress.done(); + }) +} +module.exports.updateEvents = updateEvents; + +module.exports.changePage = function (pageNum) { + store.dispatch({ + type: 'CHANGE_EVENTS_PAGE', + page: pageNum + }); + return updateEvents(); +} + +module.exports.changePageSize = function (size) { + store.dispatch({ + type: 'CHANGE_EVENTS_PAGE_SIZE', + size: size + }); + return updateEvents(); +} + +module.exports.changePageSearch = function (search) { + store.dispatch({ + type: 'CHANGE_EVENTS_PAGE_SEARCH', + search: search + }); + return updateEvents(); +} + +module.exports.viewEvents = function () { + store.dispatch({ + type: 'VIEW', + view: 'EVENTS', + subview: 'ALL', + viewID: '' + }); + return updateEvents(); +} + +module.exports.viewRawEvents = function () { + store.dispatch({ + type: 'VIEW', + view: 'RAWEVENTS', + subview: 'ALL', + viewID: '' + }); + return updateEvents(); +} + +module.exports.viewExceptions = function () { + store.dispatch({ + type: 'VIEW', + view: 'EXCEPTIONS', + subview: 'ALL', + viewID: '' + }); + return updateEvents(); +} + +module.exports.viewHelp = function () { + store.dispatch({ + type: 'VIEW', + view: 'HELP', + subview: 'ALL', + viewID: '' + }); +} + +module.exports.viewOrgByID = function (id) { + store.dispatch({ + type: 'VIEW', + view: 'ORG', + viewID: id, + subview: 'SPLIT' + }); +} + +function viewOrganizations () { + store.dispatch({ + type: 'VIEW', + view: 'ORG', + subview: 'ALL', + viewID: '' + }); +} +module.exports.viewOrganizations = viewOrganizations; + +module.exports.viewUsers = function () { + store.dispatch({ + type: 'VIEW', + view: 'USER', + subview: 'ALL', + viewID: '' + }); +} + +module.exports.viewOrgUsers = function () { + let state = store.getState(); + + store.dispatch({ + type: 'VIEW', + view: 'USER', + subview: 'ORG', + viewID: state.selectedOrg.id + }); +} + +module.exports.viewOrgFleets = function () { + let state = store.getState(); + + store.dispatch({ + type: 'VIEW', + view: 'FLEET', + subview: 'ORG', + viewID: state.selectedOrg.id + }); +} + +module.exports.viewOrgVehicles = function () { + let state = store.getState(); + + store.dispatch({ + type: 'VIEW', + view: 'VEHICLE', + subview: 'ORG', + viewID: state.selectedOrg.id + }); +} + +module.exports.viewDevices = function () { + store.dispatch({ + type: 'VIEW', + view: 'DEVICE', + subview: 'ALL', + viewID: '' + }); +} + +module.exports.viewNewOrganization = function () { + store.dispatch({ + type: 'VIEW', + view: 'ORG', + subview: 'NEW', + viewID: '' + }); +} + +module.exports.viewNewDevice = function () { + store.dispatch({ + type: 'VIEW', + view: 'DEVICE', + subview: 'NEW', + viewID: '' + }); +} + +module.exports.viewNewUser = function () { + store.dispatch({ + type: 'VIEW', + view: 'USER', + subview: 'NEW', + viewID: '' + }); +} + +module.exports.viewNewVehicle = function () { + store.dispatch({ + type: 'VIEW', + view: 'VEHICLE', + subview: 'NEW', + viewID: '' + }); +} + +module.exports.viewVehicleByID = function (id) { + store.dispatch({ + type: 'VIEW', + view: 'VEHICLE', + subview: 'EDIT', + viewID: id + }); +} + +module.exports.viewDevices = function () { + store.dispatch({ + type: 'VIEW', + view: 'DEVICE', + subview: 'ALL', + viewID: '' + }); +} + +module.exports.viewDeviceByID = function (id) { + store.dispatch({ + type: 'VIEW', + view: 'DEVICE', + subview: 'EDIT', + viewID: id + }); +} + +module.exports.viewUserByID = function (id) { + store.dispatch({ + type: 'VIEW', + view: 'USER', + subview: 'EDIT', + viewID: id + }); +} + +module.exports.viewReports = function () { + store.dispatch({ + type: 'VIEW_REPORTS', + }); +} + +module.exports.viewMap = function () { + store.dispatch({ + type: 'VIEW_MAP', + }); +} + +module.exports.viewSplitScreen = function () { + store.dispatch({ + type: 'VIEW_SPLIT_SCREEN', + }); +} + +module.exports.editOrganization = function (id) { + store.dispatch({ + type: 'VIEW', + view: 'ORG', + subview: 'EDIT', + viewID: id + }); +} + +module.exports.setAutoUpdate = function (bool) { + store.dispatch({ + type: 'AUTOUPDATE', + value: bool + }); +} + +module.exports.setShowVerbose = function (bool) { + store.dispatch({ + type: 'SHOWVERBOSE', + value: bool + }); +} + +module.exports.setShowLatLong = function (bool) { + store.dispatch({ + type: 'SHOWLATLONG', + value: bool + }); +} diff --git a/src/client/appStateReducer.js b/src/client/appStateReducer.js new file mode 100644 index 0000000..3ec27f7 --- /dev/null +++ b/src/client/appStateReducer.js @@ -0,0 +1,336 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +// Reducer for Redux +const Cookies = require('cookies-js'); +const helpers = require('../common/helpers'); +let defaultState = require('./appDefaultState'); + +if (history.state) { + defaultState = Object.freeze(Object.assign({}, defaultState, history.state)); +} + +module.exports = function reducer (state, action) { + if (!state) { + return defaultState; + } + + switch(action.type) { + case 'SOCKET_CONNECT': + return Object.assign({}, state, { realTimeUpdates : true }); + + case 'SOCKET_DISCONNECT': + return Object.assign({}, state, { realTimeUpdates : false }); + + case 'LOGOUT': + return Object.assign({}, defaultState ); + + case 'SESSION': + return Object.assign({}, state, { user : action.user }); + + case 'GET_ORG': + var orgsByID = _.cloneDeep(state.orgsByID); + orgsByID[action.org.id] = action.org; + return Object.assign({}, state, { orgsByID : orgsByID }); + + case 'SELECT_ORG': + return Object.assign({}, state, { + selectedOrg : action.org , + selectedItem: null, + vehiclesByID: {}, + selectedVehicleHistory: [] + }); + + case 'SELECT_FLEET': + var newState = {}; + newState.impliedSelectedVehicles = []; + newState.selectedFleets = [action.fleet]; + newState.selectedAllFleets = false; + newState.selectedVehicle = null; + + newState.selectedFleets.forEach(function (fleet) { + fleet.vehicles.forEach(function (vid) { + if (state.vehiclesByID[vid] != null) { + newState.impliedSelectedVehicles.push(state.vehiclesByID[vid]); + } + }) + }) + + newState.impliedSelectedVehicles = _.uniq(newState.impliedSelectedVehicles); + return Object.assign({}, state, newState); + + case 'SELECT_FLEET_ALL': + var newState = {}; + newState.selectedFleets = _.cloneDeep(_.toArray(state.fleetsByID)); + newState.impliedSelectedVehicles = []; + newState.selectedAllFleets = true; + newState.selectedVehicle = null; + newState.selectedFleets.forEach(function (fleet) { + fleet.vehicles.forEach(function (vid) { + if (state.vehiclesByID[vid] != null) { + newState.impliedSelectedVehicles.push(state.vehiclesByID[vid]); + } + }) + }) + newState.impliedSelectedVehicles = _.uniq(newState.impliedSelectedVehicles); + return Object.assign({}, state, newState); + + case 'SELECT_VEHICLE': + return Object.assign({}, state, { + selectedVehicle: state.vehiclesByID[action.id], + impliedSelectedVehicles: [state.vehiclesByID[action.id]], + view: 'ORG', + selectedAllFleets: false, + selectedFleets: [], + selectedVehicleHistory: [] + }); + + case 'USERS': + var usersByID = {}; + action.users.forEach(function (user) { + usersByID[user.username] = user; + }); + return Object.assign({}, state, { usersByID: usersByID }); + + case 'VEHICLES': + var vehiclesByID = {}; + action.vehicles.forEach(function (vehicle) { + vehiclesByID[vehicle.id] = vehicle; + }); + return Object.assign({}, state, { + vehicles : action.vehicles, + vehiclesByID: vehiclesByID, + lastUpdated: new Date() + }); + + case 'ORG_USERS': + var usersByID = _.cloneDeep(state.usersByID); + action.users.forEach(function (user) { + usersByID[user.username] = user; + }); + return Object.assign({}, state, { usersByID : usersByID }); + + case 'ORGS': + var orgs = action.orgs; + var orgsByID = {}; + orgs.forEach(function (org) { + orgsByID[org.id] = org; + }); + return Object.assign({}, state, { orgsByID : orgsByID }); + + case 'SAVE_ORG': + var orgsByID = _.cloneDeep(state.orgsByID); + orgsByID[action.org.id] = action.org; + return Object.assign({}, state, { orgsByID : orgsByID }); + + case 'SAVE_USER': + var usersByID = _.cloneDeep(state.usersByID); + usersByID[action.user.username] = action.user; + var me = state.user; + if (action.user.username === me.username) { + me = action.user; + } + return Object.assign({}, state, { + usersByID : usersByID, + user: me + }); + + case 'SAVE_VEHICLE': + var vehiclesByID = _.cloneDeep(state.vehiclesByID); + vehiclesByID[action.vehicle.id] = action.vehicle; + + var impliedSelectedVehicles = _.cloneDeep(state.impliedSelectedVehicles); + + for (let i = 0; i < impliedSelectedVehicles.length; i++) { + if (impliedSelectedVehicles[i].id == action.vehicle.id) { + impliedSelectedVehicles[i] = action.vehicle; + break; + } + } + + return Object.assign({}, state, { + vehiclesByID : vehiclesByID, + impliedSelectedVehicles: impliedSelectedVehicles + }); + + case 'DELETE_VEHICLE': + var vehiclesByID = _.cloneDeep(state.vehiclesByID); + delete vehiclesByID[action.vehicle.id]; + + var impliedSelectedVehicles = _.cloneDeep(state.impliedSelectedVehicles); + + for (let i = 0; i < impliedSelectedVehicles.length; i++) { + if (impliedSelectedVehicles[i].id == action.vehicle.id) { + delete impliedSelectedVehicles[i]; + break; + } + } + + return Object.assign({}, state, { + vehiclesByID : vehiclesByID, + impliedSelectedVehicles: impliedSelectedVehicles + }); + + case 'DELETE_USER': + var usersByID = _.cloneDeep(state.usersByID); + delete usersByID[action.user.username]; + return Object.assign({}, state, { usersByID : usersByID }); + + case 'DELETE_ORG': + var orgsByID = _.cloneDeep(state.orgsByID); + delete orgsByID[action.org.id]; + return Object.assign({}, state, { orgsByID : orgsByID }); + + case 'SAVE_DEVICE': + var devicesByID = _.cloneDeep(state.devicesByID); + devicesByID[action.device.imei] = action.device; + return Object.assign({}, state, { devicesByID : devicesByID }); + + case 'DELETE_DEVICE': + var devicesByID = _.cloneDeep(state.devicesByID); + delete devicesByID[action.device.imei]; + return Object.assign({}, state, { devicesByID : devicesByID }); + + case 'DEVICES': + var devices = action.devices; + var devicesByID = {}; + devices.forEach(function (device) { + devicesByID[device.imei] = device; + }); + return Object.assign({}, state, { devicesByID : devicesByID }); + + case 'FLEETS': + var fleets = action.fleets; + var fleetsByID = {}; + fleets.forEach(function (fleet) { + fleetsByID[fleet.id] = fleet; + }); + return Object.assign({}, state, { fleetsByID : fleetsByID }); + + case 'DELETE_FLEET': + var fleetsByID = _.cloneDeep(state.fleetsByID) + delete fleetsByID[action.fleet.id]; + return Object.assign({}, state, { fleetsByID : fleetsByID }); + + case 'SAVE_FLEET': + var fleetsByID = _.cloneDeep(state.fleetsByID) + fleetsByID[action.fleet.id] = action.fleet; + return Object.assign({}, state, { fleetsByID : fleetsByID }); + + case 'VIEW': + var isAllSiteLevel = action.subview === 'ALL' && (action.view === 'ORG' || action.view === 'USER' || action.view === 'DEVICE'); + var isAllOrgs = action.view === 'ORG' && action.subview === 'ALL'; + + return Object.assign({}, state, { + view: action.view, + subview: action.subview, + viewID: action.viewID, + selectedOrg: isAllSiteLevel ? {} : state.selectedOrg, + selectedAllFleets: isAllOrgs ? false : state.selectedAllFleets, + selectedFleets: isAllOrgs ? [] : state.selectedFleets, + selectedItem: isAllOrgs ? null : state.selectedItem, + selectedVehicle: isAllOrgs ? null : state.selectedVehicle, + selectedVehicles: isAllOrgs ? null : state.selectedVehicles, + impliedSelectedVehicles: isAllOrgs ? [] : state.impliedSelectedVehicles, + selectedVehicleHistory: isAllOrgs ? [] : state.selectedVehicleHistory, + vehiclesByID: isAllOrgs? {} : state.vehiclesByID + }); + + case 'VIEW_SPLIT_SCREEN': + return Object.assign({}, state, { + view: 'ORG', + subview: 'SPLIT' + }); + + case 'VIEW_MAP': + return Object.assign({}, state, { + view: 'ORG', + subview: 'MAP' + }); + + case 'VIEW_REPORTS': + return Object.assign({}, state, { + view: 'ORG', + subview: 'REPORT' + }); + + case 'SELECT_ITEM': + return Object.assign({}, state, { + selectedItem: action.item + }); + + case 'SELECT_DAYS': + return Object.assign({}, state, { + startDate: action.startDate, + endDate: action.endDate + }); + + case 'VEHICLE_HISTORY': + // var vehicleHistoryByID = _.cloneDeep(state.vehicleHistoryByID); + // vehicleHistoryByID[action.vehicle.id] = action.history; + // return Object.assign({}, state, { + // vehicleHistoryByID: vehicleHistoryByID + // }); + return Object.assign({}, state, { + selectedVehicleHistory: action.history, + lastUpdated: new Date(), + }); + + case 'CHANGED_VEHICLE_HISTORY': + var vehiclesByID = _.cloneDeep(state.vehiclesByID); + vehiclesByID[action.event.id] = action.event; + let newState = Object.assign({}, state, { + vehiclesByID: vehiclesByID, + lastUpdated: new Date(), + }); + newState.impliedSelectedVehicles = []; + + for (let vehicle of state.impliedSelectedVehicles) { + newState.impliedSelectedVehicles.push(vehiclesByID[vehicle.id]); + } + + return newState; + + case 'EVENTS': + return Object.assign({}, state, { + events: action.events + }); + + case 'CHANGE_EVENTS_PAGE': + return Object.assign({}, state, { + page: action.page + }); + + case 'CHANGE_EVENTS_PAGE_SIZE': + return Object.assign({}, state, { + pagesize: action.size + }); + + case 'CHANGE_EVENTS_PAGE_SEARCH': + return Object.assign({}, state, { + search: action.search + }); + + case 'EVENT_COUNT': + return Object.assign({}, state, { + eventCount: action.count + }); + + case 'AUTOUPDATE': + return Object.assign({}, state, { + autoUpdate: !!action.value + }); + + case 'SHOWVERBOSE': + return Object.assign({}, state, { + verbose: !!action.value + }); + + case 'SHOWLATLONG': + return Object.assign({}, state, { + showLatLong: !!action.value + }); + + default: + return state; + } +} diff --git a/src/client/catchhandler.js b/src/client/catchhandler.js new file mode 100644 index 0000000..0a647e8 --- /dev/null +++ b/src/client/catchhandler.js @@ -0,0 +1,16 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; + +/* + Simple promise catch handler that just displays an alert. + */ +module.exports = function (result) { + const st = JSON.stringify(result); + console.error(st) + + if (result.message) { + window.alert(result.message); + } else { + window.alert(st); + } +} diff --git a/src/client/device-new.js b/src/client/device-new.js new file mode 100644 index 0000000..ae17eb8 --- /dev/null +++ b/src/client/device-new.js @@ -0,0 +1,156 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState';const Device = require('../common/models/Device'); +const catchhandler = require('./catchhandler'); +const orgselector = require('./orgselector'); +const pikaday = require('pikaday2').default; +const _ = require('lodash'); +const moment = require('moment'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + const state = appState.getState(); + ctrl.device = new Device(state.devicesByID[state.viewID]); + + if (state.devicesByID[state.viewID]) { + ctrl.editing = true; + } else { + ctrl.editing = false; + ctrl.device = new Device(); + ctrl.device.imei = state.viewID; + } + + // appState.getStore().subscribe(function () { + // const state = appState.getState(); + // if (state.devicesByID[ctrl.device.imei]) { + // ctrl.device = state.devicesByID[ctrl.device.imei]; + // m.redraw(); + // } + // }) + + ctrl.save = function () { + appState.saveDevice(ctrl.device) + .then(function () { + window.history.back(); + }) + .catch(catchhandler); + } +}; + +const formitem = require('./formitem'); + +module.exports.view = function(ctrl) { + const state = appState.getState(); + const device = ctrl.device; + + function lastKey(key) { + switch (key) { + case 'lastACKCFG': + return t('Last seen global config acknowledgement:'); + + case 'lastACKFRI': + return t('Last seen fix report config acknowledgement:'); + + case 'lastACKSRI': + return t('Last seen server registration config acknowledgement:'); + + case 'lastHeartbeat': + return [t('Last seen heartbeat') + ' ', m('span', { + style: { + 'font-size': '1.5em', + 'color': 'red' + } + }, '♥'), ':' ]; + + case 'lastACKBSI': + return t('Last seen bearer setting (GSM data service) config acknowledgement:'); + + case 'lastGSM': + return t('Last seen GSM information acknowledgement:'); + + case 'lastPDP': + return t('Last seen GPRS connection establishment report:'); + + case 'lastACKTOW': + return t('Last seen towing config acknowledgement:'); + + case 'lastACKSPD': + return t('Last seen speeding config acknowledgement:'); + + case 'lastACKJDC': + return t('Last seen jamming config acknowledgement:'); + + default: + return key; + } + } + + return m('div', [ + m('.col-md-3'), + m('div.col-md-6 business-table', [ + m('.btn', ctrl.editing ? t('Edit Device') : t('New Device')), + m('form.form-horizontal', [ + Object.keys(device).map(function(key) { + if (key.indexOf('last') === 0) { + //lastACKCFG, lastACKFRI, lastACKSRI, lastHeartbeat, etc. + return m('div.form-group', [ + m('label.col-md-4 control-label', lastKey(key)), + m('.col-md-8', m('input[disabled][class=form-control]', { + value: device[key].senddate ? moment(device[key].senddate).format('M/DD/YYYY h:mm:ss A') : moment(device[key]).format('M/DD/YYYY h:mm:ss A') + })) + ]) + } else if (key === 'orgid') { + return orgselector(device, 4, 8); + } else if (key === 'activationDate') { + return m('div.form-group', [ + m('label.col-md-4 control-label', t('Activation Date:') + ' '), + m('.col-md-8', { + config: function (el, isInitialized) { + if (isInitialized) { + return; + } + + const input = document.createElement('input'); + input.className = 'form-control'; + el.appendChild(input); + + ctrl.datepicker = new pikaday({ + field: input, + onSelect: function () { + device.activationDate = this.getDate().toISOString(); + m.redraw(); + } + }); + + ctrl.datepicker.setDate(device.activationDate) + }, + }), + ]) + // return m('div.form-group', [m('label.col-md-2 control-label', _.capitalize(key)), m('div.col-md-10', + // ctrl.datepicker.view())]) + } else if (typeof device[key] === 'object') { + return; + } else { + return formitem(device, key, 4, 8, key === 'imei' && ctrl.editing); + } + }) + ]), + m('.buttons-right', [ + m('button.btn btn-default', { + onclick: function(e) { + window.history.back(); + } + }, t('Cancel')), + ' ', + m('button.btn btn-success', { + onclick: ctrl.save + }, t('Save')) + ]), + m('label.control-label', 'All fields:'), + m('pre', JSON.stringify(device, null, 4)) + ]), + m('.col-md-3') + ]) +}; diff --git a/src/client/devices.js b/src/client/devices.js new file mode 100644 index 0000000..7caaa5a --- /dev/null +++ b/src/client/devices.js @@ -0,0 +1,111 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState'; +const _ = require('lodash'); +const sorts = require('./sorts'); +const moment = require('moment'); +const catchhandler = require('./catchhandler'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + ctrl.delete = function (device) { + const result = window.confirm('Are you sure you want to delete ' + device.imei + '?'); + if (result === true) { + appState.deleteDevice(device) + .catch(catchhandler); + } + } +}; + +module.exports.view = function(ctrl, args, extras) { + const state = appState.getState(); + const orgid = state.selectedOrg.id; + + const vehiclesByDeviceID = {}; + + _.toArray(state.vehiclesByID).forEach(function (vehicle) { + vehiclesByDeviceID[vehicle.device] = vehicle; + }); + + + function hearbeatField(device) { + return device.lastHeartbeat ? [m('span', { + style: { + 'color': 'red', + } + }, '♥ '), moment(device.lastHeartbeat).fromNow()] : '' + } + + function batteryField(device) { + return device.batteryPercent ? m('span', { + style: { + 'margin-left': '1em' + } + }, '' + device.batteryPercent + '%🔋') : '' + } + + return m('.business-table', [ + m('button.btn btn-default', { + style: { + 'margin-bottom': '1em' + }, + onclick: function () { + appState.viewNewDevice(); + } + }, t('New Device')), + m('table.table table-bordered table-striped', sorts(_.toArray(state.devicesByID)), [ + m('thead', + m('tr', [ + m('th[data-sort-by=imei]', t('IMEI')), + m('th[data-sort-by=sim]', t('SIM')), + m('th[data-sort-by=orgid]', t('Organization')), + m('th[data-sort-by=status]', t('Active')), + m('th[data-sort-by=hearbeat]', t('Heartbeat')), + m('th[data-sort-by=batteryPercent]', t('Battery')), + m('th[data-sort-by=phone]', t('Phone')), + m('th[data-sort-by=network]', t('Network')), + m('th[data-sort-by=activationDate]', t('Activation Date')), + m('th[data-sort-by=vehicle.name]', t('Associated Vehicle')), + m('th', t('Operations')) + ]) + ), + m('tbody', [ + _.toArray(state.devicesByID).map(function(device) { + return m('tr', [m('td', device.imei), + m('td', device.sim), + m('td', appState.getOrgName(device.orgid)), + m('td', device.active ? '✔' : ''), + m('td', hearbeatField(device)), + m('td', batteryField(device)), + m('td', device.phone), + m('td', device.network), + m('td', device.activationDate ? moment(device.activationDate).format('M/DD/YYYY') : device.activationDate), + m('td', m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewVehicleByID(vehiclesByDeviceID[device.imei].id); + } + }, vehiclesByDeviceID[device.imei] ? vehiclesByDeviceID[device.imei].name : '')), + m('td', [ + m('a.btn btn-primary btn-sm btn-warning ', { + onclick: function (ev) { + ev.preventDefault(); + appState.viewDeviceByID(device.imei); + } + }, m('span.middle glyphicon glyphicon-pencil'), ' ' + t('Update')), + ' ', + m('a.btn btn-primary btn-sm btn-danger', { + onclick: function() { + ctrl.delete(device); + } + }, m('span.middle glyphicon glyphicon-trash'), ' ' + t('Delete')) + ]), + ]) + }) + ]) + ]) + ]) +}; diff --git a/src/client/events.js b/src/client/events.js new file mode 100644 index 0000000..0a602e2 --- /dev/null +++ b/src/client/events.js @@ -0,0 +1,270 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState'; +const _ = require('lodash'); +const moment = require('moment'); + +const withAuth = require('./withAuth'); +const eventreportparser = require('../helper/eventreportparser'); +const modal = require('mithril-modal'); + +const catchhandler = require('./catchhandler'); + +const Cookies = require('cookies-js'); +const fullAddress = require('../common/addressdisplay').full; + +module.exports.controller = function(args, extras) { + const ctrl = this; + ctrl.parsed = m.prop({}); + + ctrl.page = function (page) { + return appState.changePage(page); + } + + ctrl.pagesize = function (size) { + return appState.changePageSize(size); + } + + ctrl.changePage = function (page) { + return appState.changePage(page); + } + + ctrl.search = function (search) { + return appState.changePageSearch(search); + } + + ctrl.nextPage = function () { + const page = appState.getState().page; + return appState.changePage(page + 1); + } + + function geocode (id, force) { + return fetch('/api/vehiclehistory/' + id + '/geocode' + (force ? '?force=true' : ''), { + method: 'POST', + headers: { + 'authorization': 'Bearer ' + Cookies.get('jwt'), + 'content-type': 'application/json; charset=UTF-8' + } + }) + } + + ctrl.geocode = function (id, force) { + return geocode(id, force) + .then(function () { + appState.updateEvents(); + }) + .catch(catchhandler); + } + + ctrl.geocodeAll = function () { + const state = appState.getState(); + const events = state.events; + + Promise.map(events, function (event) { + if (!event.ad) { + return geocode(event.id, false); + } + }, {concurrency: 1}) + .finally(function () { + appState.updateEvents(); + }) + } +}; + +module.exports.view = function(ctrl, args, extras) { + + const state = appState.getState(); + const events = state.events; + const count = state.eventCount; + let keys = []; + const type = _.lowerCase(state.view); + const page = state.page; + const pagesize = state.pagesize; + + if (events.length > 0) { + keys = []; + events.forEach(function (item) { + keys = _.union(keys, Object.keys(item)); + }) + + if (type === 'events') { + keys.unshift('Geocode'); + } + } + + function buildPagination () { + const pages = Math.ceil(count / pagesize); + const lis = []; + for (let i = 1; i < pages + 1; i++) { + lis.push(m('li', m('a', { + style: { + "cursor": "pointer" + }, + onclick: m.withAttr('value', ctrl.changePage), + value: i + }, i))) + } + lis.push(m('li', + m('a', { + style: { + "cursor": "pointer" + }, + onclick: ctrl.nextPage, + }, '»') + )) + return m('nav', m('ul.pagination', lis)); + } + + return m('div.text-nowrap', [ + m('label', t('Selected Page'), m('input.form-control', { + type: 'number', + onchange: m.withAttr('value', ctrl.page), + value: page + })), + + m('label', t('Count per Page'), m('input.form-control', { + type: 'number', + onblur: m.withAttr('value', ctrl.pagesize), + value: pagesize + })), + + type === 'rawevents' ? m('label', t('Search by IMEI'), m('input.form-control', { + type: 'text', + onchange: m.withAttr('value', ctrl.search), + value: state.search, + onkeyup: function(ev) { + if (ev.keyCode === 13) { + appState.updateEvents(); + } else { + m.redraw.strategy('none'); + } + }, + })) : null, + + m('button.btn btn-success', { + onclick: function () { + appState.updateEvents(); + } + }, t('Refresh')), + + buildPagination(), + + type === 'events' ? m('div', 'Legend: a = azimuth, b = buffered, bp = battery percentage, d = date sent by the unit, faketow = maybe about to be towing, g = gps accuracy (1=most accurate/20=least/0=unknown or not reported), ' + + 'gss = gpsSignalStatus report (1 seeing, 0 not seeing), satelliteNumber = number of GPS satellites seeing, h = engine hours, ig = ignition, igd = ignition duration, m = distance (kilometers), mo = motion, p = powervcc, rid = report id, rty = report type, s = speed (kph)') : null, + + type === 'events' ? m('button.btn-xs', { + onclick: function (ev) { + ctrl.geocodeAll(); + } + }, t('Cached geocode visible with missing')) : null, + m('br'), + // m('nav', m('ul.pagination', [ + // m('li', m('a', { + // onclick: m.withAttr('value', ctrl.changePage), + // value: '1' + // }, '1')), + // ])), + m('div', count + ' ' + type), + + m.component(modal, { + animation: 'fadeAndScale', + style: { + dialog: { + // backgroundColor: '#aaffee', + width: '600px' + } + }, + close: '✘' + }, m.component({ + view: function () { + return m('div', m('pre', _.isObject(ctrl.parsed()) ? JSON.stringify(ctrl.parsed(), null, 4) : ctrl.parsed())); + } + })), + + m('table.table-condensed table-bordered table-striped', [ + m('thead', keys.map(function (key) { + return m('td', key) + })), + type === 'rawevents' || type ==='events' ? m('tbody', events.map(function (event) { + return m('tr', [keys.map(function (key) { + if (key === 'message') { + const msg = event[key]; + + return m('td', m('button.btn btn-xs btn-default', { + onclick: function () { + modal.show(); + let parsed; + try { + parsed = eventreportparser(msg); + delete parsed.args; + ctrl.parsed(parsed); + } catch (e) { + parsed = e; + if (e.stack) { + ctrl.parsed(e.stack); + } else { + ctrl.parsed(e.message); + } + + } + // alert(JSON.stringify(parsed, null, 4)); + } + }, t('Parse')), ' '+ msg) + } + if (key === 'ad') { + if (event[key]) { + let obj = event[key]; + let str = JSON.stringify(obj, null, 2); + return m('pre.pointer', { + onclick: function (ev) { + ev.target.innerHTML = str; + } + }, fullAddress(event) + '…') + } + } + if (key === 'd' || key === 'date') { + try { + return m('td', moment(event[key]).format('M/DD/YYYY h:mm:ss A')); + } catch (e) { + console.warn(e); + return m('td', event[key]); + } + } else if (key === 'Geocode') { + return [ + m('button.button btn-xs', { + onclick: function (ev) { + ctrl.geocode(event.id, false); + } + }, t('Cached')), + ' ', + m('button.button btn-xs', { + onclick: function (ev) { + ctrl.geocode(event.id, true); + } + }, t('Force')) + ] + } else { + return m('td', event[key]); + } + }), + ])})) : null, + + type === 'exceptions' ? m('tbody', events.map(function (event) { + return m('tr', keys.map(function (key) { + if (key === 'date') { + try { + return m('td', moment(event[key]).format('M/DD/YYYY h:mm:ss.SSS A')); + } catch (e) { + console.warn(e); + return m('td', event[key]); + } + } else { + return m('td', m('pre', key !== 'stack' && _.isObject(event[key]) ? JSON.stringify(event[key], null, 4) : event[key])) + } + })) + })) : null, + ]) + ]) +}; diff --git a/src/client/fleets.js b/src/client/fleets.js new file mode 100644 index 0000000..f52323a --- /dev/null +++ b/src/client/fleets.js @@ -0,0 +1,226 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState'; +const navbar = require('./navbar'); +const moment = require('moment'); +const _ = require('lodash'); +const withAuth = require('./withAuth'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + let creatingFleet; + + ctrl.cancel = function() { + ctrl.fleet = { + name: '', + vehicles: [] + }; + const state = appState.getState(); + ctrl.fleet.orgid = state.selectedOrg.id; + + ctrl.availableVehicles = []; + ctrl.selectedAvailableVehicles = []; + ctrl.selectedInFleetVehicles = []; + } + ctrl.cancel(); + + ctrl.getVehicleById = function (vid) { + const state = appState.getState(); + if (state.vehiclesByID[vid]) { + return state.vehiclesByID[vid]; + } else { + return {}; + } + } + + ctrl.selectFleet = function (fleet) { + const state = appState.getState(); + + ctrl.fleet = fleet; + ctrl.availableVehicles = []; + _.toArray(state.vehiclesByID).forEach(function (vehicle) { + ctrl.availableVehicles.push(vehicle.id); + }) + + ctrl.colorPickerEl().value = fleet.color; + } + + ctrl.rightArrow = function() { + while (ctrl.selectedAvailableVehicles.length) { + const vid = ctrl.selectedAvailableVehicles.pop(); + const vehicle = ctrl.getVehicleById(vid); + + ctrl.fleet.vehicles = _.union(ctrl.fleet.vehicles, [vehicle.id]) + ctrl.availableVehicles = _.without(ctrl.availableVehicles, vid); + } + } + + ctrl.leftArrow = function() { + while (ctrl.selectedInFleetVehicles.length) { + const vid = ctrl.selectedInFleetVehicles.pop(); + const vehicle = ctrl.getVehicleById(vid); + + ctrl.fleet.vehicles = _.without(ctrl.fleet.vehicles, vid); + ctrl.availableVehicles = _.union(ctrl.availableVehicles, [vid]); + } + } + + ctrl.create = function() { + ctrl.selectFleet({ + name: '', + color: '', + vehicles: [] + }) + } + + + ctrl.delete = function() { + appState.deleteFleet(ctrl.fleet); + } + + ctrl.save = function() { + const state = appState.getState(); + ctrl.fleet.orgid = state.selectedOrg.id; + appState.saveFleet(ctrl.fleet); + } + + ctrl.colorPickerEl = m.prop(); +} + +const truckSvg = require('./svg/truck'); +const getselectvalues = require('./getselectvalues'); + +module.exports.view = function(ctrl, args, extras) { + + const state = appState.getState(); + const fleets = _.toArray(state.fleetsByID); + + return m('div', [ + m('.col-sm-1'), + m('.col-sm-10', [ + m('.col-sm-4', m('.business-table', [ + m('h4', t('Fleets')), + m('ul.list-group', [ + fleets.map(function(fleet) { + return m('li.pointer list-group-item', { + class: ctrl.fleet.name === fleet.name ? 'active' : '', + onclick: function() { + ctrl.selectFleet(fleet); + } + }, [ + truckSvg(16, 16, fleet.color), + ' ', + fleet.name + ]) + }) + ]), + // ctrl.fleets().map(function(fleet) { + // return m('div', m('a.pointer', { + // onclick: function() { + // ctrl.fleet(fleet); + // } + // }, fleet.name)) + // }), + m('br'), + m('.buttons-right', [ + m('button.btn btn-sm btn-default', { + onclick: ctrl.delete, + disabled: ctrl.fleet.id == null + }, t('Delete')), + ' ', + m('button.btn btn-sm btn-success', { + onclick: ctrl.create + }, t('Create')) + ]), + m('br') + ])), + m('.col-sm-8.business-table', m('div', [ + m('.form-group.col-sm-12', [ + m('.row', [ + m('.form-group.col-sm-4', [ + m('label.control-label', t('Fleet Name') + ':'), m('div', m('input.form-control', { + disabled: ctrl.fleet.name == null, + value: ctrl.fleet.name ? ctrl.fleet.name : '', + onblur: m.withAttr('value', function (val) { + ctrl.fleet.name = val; + }) + })), + ]), + m('.form-group.col-sm-2'), + m('.form-group.col-sm-6', [ + m('label.col-sm-2 control-label', t('Fleet Color') + ':'), + m('input[type=color]', { + config: function (el, isInitialized) { + if (!isInitialized) { + ctrl.colorPickerEl(el); + } + }, + onchange: function (ev) { + ctrl.fleet.color = ev.target.value; + } + }) + ]), + ]) + ]), + + m('.form-group', [ + m('.col-sm-5', [ + m('div', t('Available Vehicles')), + m('select.fullwidth.form-control[multiple][size=20]', { + onblur: function (ev) { + ctrl.selectedAvailableVehicles = getselectvalues(ev.target); + } + }, ctrl.availableVehicles.map(function (vid) { + return m('option', { + value: vid + }, ctrl.getVehicleById(vid).name) + })), + ]), + m('.col-sm-2.verticalcenter', { + style: { + 'margin-top': '10em' + } + }, [ + m('button.btn-lg btn-default', { + onclick: ctrl.rightArrow + }, '→'), + ' ', + m('button.btn-lg btn-default', { + onclick: ctrl.leftArrow + }, '←') + ]), + m('.col-sm-5', [ + m('div', t('Vehicles in Fleet')), + m('select.fullwidth.form-control[multiple][size=20]', { + onblur: function (ev) { + ctrl.selectedInFleetVehicles = getselectvalues(ev.target); + } + }, ctrl.fleet.vehicles.map(function (vid) { + return m('option', { + value: vid + }, ctrl.getVehicleById(vid).name) + })), + ]) + ]), + + m('.buttons-right', { + style: { + 'margin-top': '2em' + } + }, [ + m('button.btn btn-sm btn-default', { + onclick: ctrl.cancel + }, t('Cancel')), + ' ', + m('button.btn btn-sm btn-success', { + disabled: ctrl.fleet.name.trim() === '', + onclick: ctrl.save + }, t('Save')) + ]) + ])), + ]), + m('.col-sm-1') + ]) +}; diff --git a/src/client/formatDate.js b/src/client/formatDate.js new file mode 100644 index 0000000..97437fa --- /dev/null +++ b/src/client/formatDate.js @@ -0,0 +1,13 @@ +'use strict'; +const isUserMetric = require('./isUserMetric'); +const moment = require('moment'); + +function formatDate(item) { + if (isUserMetric()) { + return moment(item).format('YYYY-MM-DD HH:mm:ss') + } else { + return moment(item).format('M/DD/YYYY h:mm:ss A') + } +} + +module.exports = formatDate; diff --git a/src/client/formitem.js b/src/client/formitem.js new file mode 100644 index 0000000..de1a47a --- /dev/null +++ b/src/client/formitem.js @@ -0,0 +1,26 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +const _ = require('lodash'); +const keyhelper = require('./keyhelper'); + +module.exports = function(obj, key, col1, col2, disabled) { + col1 = col1 || 2; + col2 = col2 || 10; + + return m('div.form-group', m('label.col-md-' + col1 + ' control-label', t(keyhelper(key)) + ':'), m('div.col-md-' + col2, (obj[key] === true || obj[key] === false) ? m('input[type=checkbox]', { + disabled: disabled, + onclick: function() { + obj[key] = this.checked; + }, + checked: obj[key] === true + }) : + m('input.form-control', { + onchange: function (ev) { + obj[key] = ev.target.value; + }, + disabled: disabled, + value: obj[key] + }))) +} diff --git a/src/client/getselectvalues.js b/src/client/getselectvalues.js new file mode 100644 index 0000000..4b2ccac --- /dev/null +++ b/src/client/getselectvalues.js @@ -0,0 +1,17 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; + +module.exports = function(select) { + const result = []; + const options = select && select.options; + let opt; + + for (let i = 0, iLen = options.length; i < iLen; i++) { + opt = options[i]; + + if (opt.selected) { + result.push(opt.value); + } + } + return result; +} diff --git a/src/client/help.js b/src/client/help.js new file mode 100644 index 0000000..4f90103 --- /dev/null +++ b/src/client/help.js @@ -0,0 +1,34 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const m = require('mithril'); + +module.exports.controller = function(args, extras) {}; + +module.exports.view = function(ctrl, args, extras) { + return m('div', [ + m('.col-sm-2'), + m('div.business-table.col-sm-8', + m('h4', 'Why don\'t I see fuel level for my vehicle?'), + m('div', 'It depends on the vehicle. Not all vehicles report their fuel level.'), + m('h4', 'What does the battery level indicate?'), + m('div', 'The battery power of the GPS tracking device.'), + m('h4', 'What does the mileage column for ignition events indicate?'), + m('div', 'The duration, in the format of HH:MM:SS, is time spent with the ignition in the prior state. For example, if the status is "ign off", this means the ignition was turned off. The duration then shows how long the ignition ran (prior to being turned off). ' + + 'If the status is "Ign on," the time duration indicates how long the ignition was off.'), + // m('h4', 'What does possibly towing mean?'), + // m('div', 'This means the vehicle tracking device thinks towing (vehicle tracking device is moving and the ignition is off) might be occuring.'), + m('h4', 'What does "verbose" show?'), + m('div', 'This shows the odometer and engine hours columns, as well as displaying more detailed informational messages from the trackers.'), + m('h4', 'What is a harsh status?'), + m('div', 'The tracking device detected what it was programmed to be harsh acceleration, braking, or turning.'), + // m('h4', 'What does ignition uncertain mean?'), + // m('div', 'The vehicle tracking device does not have a confident read on the ignition. Check the wiring.'), + m('h4', 'What is advanced mode?'), + m('div', 'This is toggled on a user\'s profile, and enables extra options in the vehicle history view.'), + m('h4', 'In advanced mode, what does calculate distances between mean?'), + m('div', 'The mileage column shows mileage changed between events, then a vertical bar, then the trip mileage. E.g., 6|18 means the vehicle moved 6 miles and the trip mileage is at 18. The trips are normally calculated as distance between starts and stops, but you can have it calculated between ignition on and off instead.') + // m('h4', 'In advanced mode, what does rollup stationary events do?'), + // m('div', 'Idling and parked events are normally combined into a single row, with the mileage column showing the HH:MM:SS of time spent idling or parked.') + ) + ]) +}; diff --git a/src/client/i18n.js b/src/client/i18n.js new file mode 100644 index 0000000..029643c --- /dev/null +++ b/src/client/i18n.js @@ -0,0 +1,237 @@ +'use strict'; +import translatejs from 'translate.js'; +import appState from './appState'; + +const messages = { + + 'en-US': { + 'Address': 'Address', + 'Advanced UI Mode': 'Advanced UI Mode', + 'Are you sure you wish to logout?': 'Are you sure you wish to logout?', + 'Alerts': 'Alerts', + 'Authorizing...': 'Authorizing...', + 'Auto Update Map': 'Auto Update Map', + 'Battery': 'Battery', + 'Back to Organizations': 'Back to Organizations', + 'Buffered': 'Buffered', + 'Calculate distances between: ': 'Calculate distances between: ', + 'City': 'City', + 'Connectivity lost': 'Connectivity lost.', + 'Devices': 'Devices', + 'Excel': 'Excel', + 'Executing...': 'Executing...', + 'Fleets': 'Fleets', + 'Fleets/All': 'Fleets/All', + 'GPS': 'GPS', + 'Help': 'Help', + 'Highlight starts': 'Highlight starts', + 'Highlight ignition': 'Highlight ignition', + 'Hour Meter': 'Hour Meter', + 'Ignition': 'Ignition', + 'Last 2 Days': 'Last 2 Days', + 'Last 3 Days': 'Last 3 Days', + 'Last month': 'Last month', + 'Last update': 'Last update', + 'Last week': 'Last week', + 'Lat': 'Lat', + 'LAT/LONG': 'LAT/LONG', + 'Log In': 'Log In', + 'Logout': 'Logout {name}', + 'Log Out': 'Log Out', + 'Long': 'Long', + 'Map': 'Map', + 'Messages': 'Messages', + 'metric': 'Metric', + 'Name': 'Name', + 'Odometer': 'Odometer', + 'Online': 'Online', + 'Organizations': 'Organizations', + 'Processed Messages': 'Processed Messages', + 'Profile': 'Profile', + 'Reports': 'Reports', + 'Raw': 'Raw', + 'Raw Messages': 'Raw Messages', + 'Refresh': 'Refresh', + 'Remember Me': 'Remember Me', + 'Reverse Order': 'Reverse Order', + 'Rollup idling & parked': 'Rollup idling & parked', + 'Run!': 'Run!', + 'Showing:': 'Showing:', + 'Split Screen': 'Split Screen', + 'Status': 'Status', + 'State': 'State', + 'Start/Stop': 'Start/Stop', + 'This week to date': 'This week to date', + 'This month': 'This month', + 'Today': 'Today', + 'Through the end of:': 'Through the end of:', + 'Users': 'Users', + 'Uncaught Exceptions': 'Uncaught Exceptions', + 'Vehicles': 'Vehicles', + 'Verbose': 'Verbose', + 'Yes': 'Yes', + 'Yesterday': 'Yesterday', + 'Welcome': 'Welcome {name}' + }, + + ru: { + 'Activation Date': 'Дата активации', + 'Active': 'Активированный', + 'Address': 'Адрес', + 'Advanced UI Mode': 'Расширенный режим UI', + 'Alerts': 'Оповещения', + 'Are you sure you wish to logout?': 'Вы уверены, что вы хотите выйти из системы ?', + 'Associated Vehicle': 'Связанный Автомобиль', + 'Auto Update Map': 'Автоматически обнавлять карту', + 'Authorizing...': 'Авторизация...', + 'Available Vehicles': 'Нераспределенные машины', + 'Battery': 'Аккумулятор', + 'Back to Organizations': 'Вернуться к Oрганизациям', + 'Begin Day End Day Report': 'Отчет начала и конца дня', + 'Buffered': 'Буферизированный', + 'Calculate distances between: ': 'Вычислить расстояние между : ', + 'Cancel': 'Отменить', + 'City': 'Город', + 'Connectivity lost': 'Соединение потеряно', + 'Count per Page': 'Количество на каждой странице', + 'Create Organization': 'Создать организацию', + 'Date': 'Дата', + 'Delete': 'Удалить', + 'Devices': 'Транспондеры', + 'Device IMEI': 'Номер трансподера', + 'Dir': 'Направление', + 'Duration': 'продолжительность', + 'Email': 'Эл. адрес', + 'End Date': 'Дата окончания', + 'Excel': 'Excel', + 'Executing...': 'Обрабатывается...', + 'First Name': 'Имя', + 'Fleet Color': 'Цвет автопарка', + 'Fleet Name': 'Имя Автопарка', + 'Fleets': 'Автопарки', + 'Fleets/All': 'Все Автопарки', + 'GPS': 'GPS', + 'Heartbeat': 'Пульс', + 'Help': 'Помощь', + 'Highlight starts': 'Выделить статус старт', + 'Highlight ignition': 'Выделить статус зажигания', + 'Hour Meter': 'Счетчик', + 'Idle Report': 'Отчет холостого хода', + 'Idling': 'На холостом ходу', + 'IMEI': 'Номер трансподера', + 'Ignition': 'Зажигание', + 'Ignition Detail Report': 'Отчет зажигания', + 'Ign off': 'Зажигание выключено', + 'Ign Off': 'Зажигание выключено', + 'Ign on': 'Зажигание включено', + 'Ign On': 'Зажигание включено', + 'Kilometers': 'километров', + 'Last Name': 'Фамилия', + 'Last 2 Days': 'Прошлые 2 дня', + 'Last 3 Days': 'Прошлые 3 дня', + 'Last month': 'Прошлый месяц', + 'Last update': 'Последнее обновление', + 'Last week': 'Прошлая неделя', + 'Lat': 'Широта', + 'LAT/LONG': 'Координаты', + 'License Plate': 'Номерной знак', + 'Location': 'Место нахождения', + 'Log In': 'Войти', + 'Log out': 'Выйти', + 'Log Out': 'Текущая Сессия', + 'Long': 'Долгота', + 'Map': 'Карта', + 'Manage': 'Управление', + 'Messages': 'Сообжения', + 'metric': 'метрический', + 'Mileage by State Summary Report': 'Отчет километража по областям', + 'Miles': 'Километраж', + 'Moving': 'В движении', + 'Name': 'Имя', + 'Network': 'Провайдер', + 'New Device': 'Создать Транспондер', + 'New User': 'Создать Пользователя', + 'New Vehicle': 'Создать машину', + 'OBD-II Engine Report': 'OBD-II Двигатель отчет', + 'OBD-II Status Report': 'OBD-II отчет', + 'Odometer by State Summary Report': 'Одометр Государственным сводном отчете', + 'Odometer': 'Одометр', + 'Online': 'Онлайн', + 'Organizations': 'Организации', + 'Organization': 'Организация', + 'Parked': 'Припаркованный', + 'Password': 'пароль', + 'Phone': 'Телефон', + 'Plate': 'Номерной знак', + 'Power connected': 'Питание подключено', + 'Power disconnected': 'Питание отключено', + 'Power off': 'Отключён', + 'Power on': 'Включён', + 'Processed Messages': 'Обработанные Сообщения', + 'Profile': 'Профайл', + 'Quick select': 'Быстрый выбор', + 'Reports': 'Отчеты', + 'Raw': 'Необработанные', + 'Raw Messages': 'Необработанные Сообщения', + 'Refresh': 'Обновить', + 'Remember Me': 'Оставаться в системе', + 'Reverse Order': 'Обратный порядок', + 'Rollup idling & parked': 'Компрессировать статусы', + 'Run!': 'Старт', + 'Save': 'Сохранить', + 'Search': 'Поиск', + 'Security Level': 'Привилегии', + 'Selected Page': 'Выбранная страница', + 'SIM': 'СИМ', + 'Showing:': 'Показывает:', + 'Speed': 'Скорость', + 'Speed Report': 'Отчет превышения скорости', + 'Split Screen': 'Разделенный Экран', + 'Status': 'Статус', + 'State': 'Область', + 'Start/Stop': 'Старт/Стоп', + 'Start/Stop Detail Report': 'Старт/стоп отчет', + 'Start': 'Тронулся', + 'Start Date': 'Дата начала', + 'Stopped': 'Остановился', + 'This week to date': 'Текущая неделя', + 'This month': 'Текущий месяц', + 'Today': 'Cегодня', + 'Towing': 'буксировка', + 'Through the end of:': 'До:', + 'Users': 'Пользователи', + 'Uncaught Exceptions': 'Ошибки', + 'Vehicle': 'Машины', + 'Vehicles': 'Машины', + 'Verbose': 'Подробный режим', + 'Yes': 'Да', + 'Yesterday': 'Вчера', + 'Welcome': 'Добро пожаловат {name}', + 'Update': 'Обновить', + 'Username': 'Имя пользователя', + 'Operations': 'Действие', + 'Vehicle': 'Средство передвижения', + 'Vehicle Summary Report': 'Краткий отчет машины', + 'Vehicles in Fleet': 'Машины в автопарке', + 'VIN': 'VIN номер' + } +} + +const options = { + // These are the defaults: + debug: true, //[Boolean]: Logs missing translations to console and add "@@" around output, if `true`. + array: false, //[Boolean]: Returns translations with placeholder-replacements as Arrays, if `true`. + pluralize: function(n,translKey){ return Math.abs(n); } //[Function(count,translationKey)]: Provides a custom pluralization mapping function. +} + +export function translate() { + const state = appState.getState(); + const lang = state.lang; + const t = translatejs(messages[lang], [options]); + + return t.apply(null, arguments); +} + +export function hasLang (key) { + return !!messages[key]; +} diff --git a/src/client/isUserMetric.js b/src/client/isUserMetric.js new file mode 100644 index 0000000..4643b4c --- /dev/null +++ b/src/client/isUserMetric.js @@ -0,0 +1,8 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const appState = require('../client/appState'); + +module.exports = function isUserMetric(value) { + const state = appState.getState(); + return state.user && state.user.metric; +} diff --git a/src/client/keyhelper.js b/src/client/keyhelper.js new file mode 100644 index 0000000..1d98800 --- /dev/null +++ b/src/client/keyhelper.js @@ -0,0 +1,71 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; + +const l = { +// id + "id": "ID", + "imei": "IMEI", +// orgs + "name": "Name", + "ein": "EIN", + "address1": "Address Line 1", + "address2": "Address Line 2", + "city": "City", + "state": "State", + "zip": "ZIP Code", + "country": "Country", + + // users + "username": "Username", + "password": "Password", + "email": "E-mail", + "firstname": "First Name", + "lastname": "Last Name", + "workphone": "Work Phone Number", + "mobilephone": "Mobile Phone Number", + "fax": "Fax Number", + "isAdmin": "Site Admin", + "isOrgAdmin": "Org Admin", + "advancedMode": "Advanced UI Mode", + + // devices + "sim": "SIM", + "phone": "Phone Number", + "network": "Network Provider (Carrier)", + "active": "Active", + "status": "Status", + + // vehicles + "device": "Link to Device (IMEI)", + "plate": "License Plate", + "vin": "VIN", + "vehicleType": "Type of vehicle (truck, trailer, etc.)", + "odometer": "Odometer", + "installLocation": "Install Location", + "hookedAsset": "Hooked Asset", + "document": "Document", + "seat": "Seat", + "length": "Length", + "width": "Width", + "gvWeight": "GV Weight", + "gcWeight": "GC Weight", + "engineHours": "Engine Hours", + "hazardLevel": "Hazard Level", + "navigationKey": "Navigation Key", + "navigationNumber": "Navigation Number", + "unreadMessagePrompt": "Unread Message Prompt", + "disableHos": "Disable Hos", + "forceMessageReadStatus": "Force Message Read Status", + "enableAssignedDriverIgnition": "Enable Assigned Driver Ignition", + "enableTollFuelTab": "Enable Toll Fuel Tab", + "allowCoDriving": "Allow Co Driving", + "driverLoginEnforced": "Driver Login Enforced", + "enableFuelSensor": "Enable Fuel Sensor", + "axies": "Axies" +} + +module.exports = function (key) { + if(l[key]) return l[key] + else return key; + +} diff --git a/src/client/locations.js b/src/client/locations.js new file mode 100644 index 0000000..98e1f59 --- /dev/null +++ b/src/client/locations.js @@ -0,0 +1,13 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const m = require('mithril'); + +module.exports.controller = function(args, extras) { +} + +module.exports.view = function(ctrl, args, extras) { + return m('div', + // m.component(navbar), + m('div', 'Locations not yet implemented') + ) +}; diff --git a/src/client/main.js b/src/client/main.js new file mode 100644 index 0000000..cf1cd8e --- /dev/null +++ b/src/client/main.js @@ -0,0 +1,35 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +require('es6-object-assign').polyfill(); +require('setimmediate'); +require('bootstrap/less/bootstrap.less'); +require('pikaday2/css/pikaday.css'); +require('./style.css'); +require('isomorphic-fetch'); + +// require('nprogress/nprogress.css'); + +window.Promise = require('bluebird'); +window.Promise.config({ + cancellation: true, // animation relies on promise cancellation. + longStackTraces: true, + warnings: false +}); + +const m = require('mithril'); + +m.deferred.onerror = function(e) { + Promise.reject(e); +} + +const appState = require('./appState'); + +m.mount(document.getElementById('root'), require('./root')); + +require('./markers/OrgMarkers'); +require('./appSocketState'); + +// if ('scrollRestoration' in history) { +// // Back off, browser, I got this... +// // history.scrollRestoration = 'manual'; +// } diff --git a/src/client/map.js b/src/client/map.js new file mode 100644 index 0000000..d9bee5f --- /dev/null +++ b/src/client/map.js @@ -0,0 +1,89 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const _ = require('lodash'); +const raf = require('raf') +const Velocity = require('velocity-animate'); +const markersByVehicle = Object.create(null); + +let mapLoaded = false; +let visible = false; + +let map; +let mapElement; +let queued; + +let readyResolver; +let ready = new Promise(function (resolver, rejecter) { + readyResolver = resolver; +}); + +module.exports.mount = function (el) { + el.style.height = '400px'; + map = new google.maps.Map(el, { + zoom: 4, + center: {lat: 50, lng: -98.35}, + rotateControl: true + }); + + // Default map type. + // map.setMapTypeId(google.maps.MapTypeId.HYBRID); + // map.setMapTypeId(google.maps.MapTypeId.TERRAIN); + + mapElement = el; + + if (queued) { + setVisible(queued[0], queued[1]) + .then(function () { + readyResolver(mapElement); + }) + } +} + +module.exports.getMap = function () { + return map; +} + +module.exports.getReady = function () { + return ready; +} + +function setVisible(bool, tall) { + visible = bool; + + if (!mapElement) { + queued = [bool, tall]; + return; + } + + mapElement.style.visibility = bool ? '' : 'hidden'; + + let height; + + if (tall) { + height = (window.innerHeight - 300); + if (height < 200) + height = 200; + } else { + height = 400; + } + height = height + 'px'; + + mapElement.style.height = bool ? height : '0'; + + // Force a repaint + mapElement.style.display = 'none'; + mapElement.offsetHeight; // no need to store this anywhere, the reference is enough + mapElement.style.display = ''; + + // Trigger resize + google.maps.event.trigger(map,'resize') + + // Wait until requestAnimationFrame to allow map to draw + ready = new Promise(function(resolver, rejecter) { + raf(function tick() { + resolver(); + }) + }) + return ready; +} +module.exports.setVisible = setVisible; diff --git a/src/client/markers/OrgMarkers.js b/src/client/markers/OrgMarkers.js new file mode 100644 index 0000000..9eafbed --- /dev/null +++ b/src/client/markers/OrgMarkers.js @@ -0,0 +1,112 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const TheMap = require('../map'); +const toGoogle = require('../togoogle'); +const MarkerWithLabel = require('./markerWithLabel'); +const Status = require('../../common/status'); +const ClickListenerFactory = require('./clicklistenerfactory'); +const appState = require('../appState.js'); + +const store = appState.getStore(); + +function create(item) { + const map = TheMap.getMap(); + let position; + if (item.last) { + position = toGoogle(item.last); + } else { + position = toGoogle(item); + } + + if (!position) { + console.warn('Org marker, invalid position ' + JSON.stringify(item)); + return; + } + + const marker = new MarkerWithLabel({ + position: position, + map: map, + title: item.name, + labelContent: item.name, + labelAnchor: new google.maps.Point(0, 0), + labelClass: 'maplabel', // the CSS class for the label + labelInBackground: false + }) + + marker.setIcon(Status.getMarkerIconFleetView(item.last)); + google.maps.event.addListener(marker, 'click', ClickListenerFactory.create(marker, item, position)); + + return marker; +} + +// const lastSelectedFleets = null; +let markersByVehicleID = {}; + +module.exports.clickMarkerByVehicleID = function (id) { + const marker = markersByVehicleID[id]; + + if (marker) { + new google.maps.event.trigger(marker, 'click'); + TheMap.getMap().panTo(marker.position); + } +} + +let lastState = require('../appDefaultState'); + +store.subscribe(function () { + TheMap.getReady().then(function () { + const state = store.getState(); + + const lastImpliedSelectedVehicles = lastState.impliedSelectedVehicles; + const lastStateVehicleStatusByID = lastState.vehiclesByID; + + if (lastImpliedSelectedVehicles !== state.impliedSelectedVehicles || + lastStateVehicleStatusByID !== state.vehiclesByID + ) { + + if (!state.autoUpdate && lastImpliedSelectedVehicles === state.impliedSelectedVehicles) { + // if we're looking at the same vehicles, but not autoupdating the map, don't do anything + return; + } + + // need to clear old markers + _.toArray(markersByVehicleID).forEach(function (marker) { + marker.setMap(null); + }) + markersByVehicleID = {}; + } + + lastState = state; + + + // if (state.vehiclesByID === lastStateVehicleStatusByID) { + // // vehicle status are the same, don't need to + // return; + // } + + if (state.selectedFleetsAll || state.selectedFleets.length > 0) { + // lastSelectedFleets = _.cloneDeep(state.selectedFleets); + + const bounds = new google.maps.LatLngBounds(); + const vehicles = state.impliedSelectedVehicles; + + state.impliedSelectedVehicles.forEach(function (vehicle) { + if (state.vehiclesByID[vehicle.id]) { + const marker = create(state.vehiclesByID[vehicle.id], false); + if (marker) { + bounds.extend(marker.position); + if (markersByVehicleID[vehicle.id]) { + markersByVehicleID[vehicle.id].setMap(null); // TODO why necessary + } + markersByVehicleID[vehicle.id] = marker; + } + } + }) + + Promise.delay(0) + .then(function () { + TheMap.getMap().fitBounds(bounds); + }) + } + }); +}); diff --git a/src/client/markers/clicklistenerfactory.js b/src/client/markers/clicklistenerfactory.js new file mode 100644 index 0000000..4b01e1d --- /dev/null +++ b/src/client/markers/clicklistenerfactory.js @@ -0,0 +1,125 @@ +'use strict'; +/* Copyright (c) 2016 Grant Miner */ +import {translate as t} from '../i18n'; +const TheMap = require('../map'); +const m = require('mithril'); +const moment = require('moment'); +const Status = require('../../common/status'); +const hidenan = require('../../common/hidenan'); +const tomiles = require('../tomiles'); +const isUserMetric = require('../isUserMetric'); +const appState = require('../appState'); +const _ = require('lodash'); +let lastinfowindow; + +function closeInfoWindow() { + if (lastinfowindow) lastinfowindow.close(); +} +module.exports.closeInfoWindow = closeInfoWindow; + +module.exports.create = function (marker, item, position) { + return function () { + if (!item.last) { + item.last = _.cloneDeep(item); + } + + const map = TheMap.getMap(); + map.setCenter(position); + const el = document.createElement('div'); + let mapel; + + m.render(el, [ + m('div', m('a', { + onclick: function (ev) { + appState.selectVehicleByID(item.id); + ev.preventDefault(); + } + }, item.name)), + m('div', { config: function (el) { + mapel = el; + }, style: 'height:130px;width:360px' }), + m('div', [ + m('div', { + style: { + color: Status.getStatusColor(item) + } + }, t(Status.getStatus(item))), + ' ' + hidenan(tomiles(item.last.s)) + ' ' + (isUserMetric() ? t('km/h') : t('mph')), + m('div', {style: { + 'float': 'right' + }}, moment(item.last.d).format('M/DD/YYYY h:mm:ss A')), + m('div', { + style: { + 'text-align': 'center' + } + },[ + t('Zoom in:') + ' ', + m('a', { + onclick: function () { + const center = new google.maps.LatLng(item.last.la + 0.0003, item.last.lo) + map.setCenter(center); + map.setZoom(18); + map.setMapTypeId(google.maps.MapTypeId.ROADMAP); + } + }, t('Road')), ' | ', + m('a', { + onclick: function () { + const center = new google.maps.LatLng(item.last.la + 0.0003, item.last.lo) + map.setCenter(center); + map.setZoom(18); + map.setMapTypeId(google.maps.MapTypeId.SATELLITE); + } + }, t('Satellite')), ' | ', + m('a', { + onclick: function () { + const center = new google.maps.LatLng(item.last.la + 0.0003, item.last.lo) + map.setCenter(center); + map.setZoom(18); + map.setMapTypeId(google.maps.MapTypeId.HYBRID); + } + }, t('Hybrid')), ' | ', + m('a', { + onclick: function () { + const center = new google.maps.LatLng(item.last.la + 0.0003, item.last.lo) + map.setCenter(center); + map.setZoom(18); + map.setMapTypeId(google.maps.MapTypeId.TERRAIN); + } + }, t('Terrain')), ' ', + ]) + ]) + ]) + + const streetViewService = new google.maps.StreetViewService(); + const STREETVIEW_MAX_DISTANCE = 100; + const infowindow = new google.maps.InfoWindow({ + content: el + }); + + streetViewService.getPanoramaByLocation(position, STREETVIEW_MAX_DISTANCE, function (streetViewPanoramaData, status) { + if (status === google.maps.StreetViewStatus.OK) { + const pano = new google.maps.StreetViewPanorama(mapel, { + pov: { + heading: item.last.a, + pitch: 0 + } + }); + // pano.bindTo('position', marker); // this causes the marker to move to the streetview + // pano.bindTo('position', streetViewPanoramaData.location); + pano.setPosition(streetViewPanoramaData.location.latLng); + pano.setVisible(true); + + google.maps.event.addListener(infowindow, 'closeclick', function() { + pano.unbind("position"); + pano.setVisible(false); + }); + } else { + mapel.style.display = 'none'; + } + }); + + closeInfoWindow(); + infowindow.open(map, this); + lastinfowindow = infowindow; + } +} diff --git a/src/client/markers/markerWithLabel.js b/src/client/markers/markerWithLabel.js new file mode 100644 index 0000000..f7ce0f9 --- /dev/null +++ b/src/client/markers/markerWithLabel.js @@ -0,0 +1,580 @@ +/** + * @name MarkerWithLabel for V3 + * @version 1.1.9 [June 30, 2013] + * @author Gary Little (inspired by code from Marc Ridey of Google). + * @copyright Copyright 2012 Gary Little [gary at luxcentral.com] + * @fileoverview MarkerWithLabel extends the Google Maps JavaScript API V3 + * google.maps.Marker class. + *

+ * MarkerWithLabel allows you to define markers with associated labels. As you would expect, + * if the marker is draggable, so too will be the label. In addition, a marker with a label + * responds to all mouse events in the same manner as a regular marker. It also fires mouse + * events and "property changed" events just as a regular marker would. Version 1.1 adds + * support for the raiseOnDrag feature introduced in API V3.3. + *

+ * If you drag a marker by its label, you can cancel the drag and return the marker to its + * original position by pressing the Esc key. This doesn't work if you drag the marker + * itself because this feature is not (yet) supported in the google.maps.Marker class. + */ + +/*! + * + * 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. + */ + +/*jslint browser:true */ +/*global document,google */ + +/** + * @param {Function} childCtor Child class. + * @param {Function} parentCtor Parent class. + */ +function inherits(childCtor, parentCtor) { + /** @constructor */ + function tempCtor() {} + tempCtor.prototype = parentCtor.prototype; + childCtor.superClass_ = parentCtor.prototype; + childCtor.prototype = new tempCtor(); + /** @override */ + childCtor.prototype.constructor = childCtor; +} + +/** + * This constructor creates a label and associates it with a marker. + * It is for the private use of the MarkerWithLabel class. + * @constructor + * @param {Marker} marker The marker with which the label is to be associated. + * @param {string} crossURL The URL of the cross image =. + * @param {string} handCursor The URL of the hand cursor. + * @private + */ +function MarkerLabel_(marker, crossURL, handCursorURL) { + this.marker_ = marker; + this.handCursorURL_ = marker.handCursorURL; + + this.labelDiv_ = document.createElement("div"); + this.labelDiv_.style.cssText = "position: absolute; overflow: hidden;"; + + // Set up the DIV for handling mouse events in the label. This DIV forms a transparent veil + // in the "overlayMouseTarget" pane, a veil that covers just the label. This is done so that + // events can be captured even if the label is in the shadow of a google.maps.InfoWindow. + // Code is included here to ensure the veil is always exactly the same size as the label. + this.eventDiv_ = document.createElement("div"); + this.eventDiv_.style.cssText = this.labelDiv_.style.cssText; + + // This is needed for proper behavior on MSIE: + this.eventDiv_.setAttribute("onselectstart", "return false;"); + this.eventDiv_.setAttribute("ondragstart", "return false;"); + + // Get the DIV for the "X" to be displayed when the marker is raised. + this.crossDiv_ = MarkerLabel_.getSharedCross(crossURL); +} +inherits(MarkerLabel_, google.maps.OverlayView); + +/** + * Returns the DIV for the cross used when dragging a marker when the + * raiseOnDrag parameter set to true. One cross is shared with all markers. + * @param {string} crossURL The URL of the cross image =. + * @private + */ +MarkerLabel_.getSharedCross = function (crossURL) { + let div; + if (typeof MarkerLabel_.getSharedCross.crossDiv === "undefined") { + div = document.createElement("img"); + div.style.cssText = "position: absolute; z-index: 1000002; display: none;"; + // Hopefully Google never changes the standard "X" attributes: + div.style.marginLeft = "-8px"; + div.style.marginTop = "-9px"; + div.src = crossURL; + MarkerLabel_.getSharedCross.crossDiv = div; + } + return MarkerLabel_.getSharedCross.crossDiv; +}; + +/** + * Adds the DIV representing the label to the DOM. This method is called + * automatically when the marker's setMap method is called. + * @private + */ +MarkerLabel_.prototype.onAdd = function () { + let me = this; + let cMouseIsDown = false; + let cDraggingLabel = false; + let cSavedZIndex; + let cLatOffset, cLngOffset; + let cIgnoreClick; + let cRaiseEnabled; + let cStartPosition; + let cStartCenter; + // Constants: + let cRaiseOffset = 20; + let cDraggingCursor = "url(" + this.handCursorURL_ + ")"; + + // Stops all processing of an event. + // + let cAbortEvent = function (e) { + if (e.preventDefault) { + e.preventDefault(); + } + e.cancelBubble = true; + if (e.stopPropagation) { + e.stopPropagation(); + } + }; + + let cStopBounce = function () { + me.marker_.setAnimation(null); + }; + + this.getPanes().overlayImage.appendChild(this.labelDiv_); + this.getPanes().overlayMouseTarget.appendChild(this.eventDiv_); + // One cross is shared with all markers, so only add it once: + if (typeof MarkerLabel_.getSharedCross.processed === "undefined") { + this.getPanes().overlayImage.appendChild(this.crossDiv_); + MarkerLabel_.getSharedCross.processed = true; + } + + this.listeners_ = [ + google.maps.event.addDomListener(this.eventDiv_, "mouseover", function (e) { + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + this.style.cursor = "pointer"; + google.maps.event.trigger(me.marker_, "mouseover", e); + } + }), + google.maps.event.addDomListener(this.eventDiv_, "mouseout", function (e) { + if ((me.marker_.getDraggable() || me.marker_.getClickable()) && !cDraggingLabel) { + this.style.cursor = me.marker_.getCursor(); + google.maps.event.trigger(me.marker_, "mouseout", e); + } + }), + google.maps.event.addDomListener(this.eventDiv_, "mousedown", function (e) { + cDraggingLabel = false; + if (me.marker_.getDraggable()) { + cMouseIsDown = true; + this.style.cursor = cDraggingCursor; + } + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + google.maps.event.trigger(me.marker_, "mousedown", e); + cAbortEvent(e); // Prevent map pan when starting a drag on a label + } + }), + google.maps.event.addDomListener(document, "mouseup", function (mEvent) { + let position; + if (cMouseIsDown) { + cMouseIsDown = false; + me.eventDiv_.style.cursor = "pointer"; + google.maps.event.trigger(me.marker_, "mouseup", mEvent); + } + if (cDraggingLabel) { + if (cRaiseEnabled) { // Lower the marker & label + position = me.getProjection().fromLatLngToDivPixel(me.marker_.getPosition()); + position.y += cRaiseOffset; + me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position)); + // This is not the same bouncing style as when the marker portion is dragged, + // but it will have to do: + try { // Will fail if running Google Maps API earlier than V3.3 + me.marker_.setAnimation(google.maps.Animation.BOUNCE); + setTimeout(cStopBounce, 1406); + } catch (e) {} + } + me.crossDiv_.style.display = "none"; + me.marker_.setZIndex(cSavedZIndex); + cIgnoreClick = true; // Set flag to ignore the click event reported after a label drag + cDraggingLabel = false; + mEvent.latLng = me.marker_.getPosition(); + google.maps.event.trigger(me.marker_, "dragend", mEvent); + } + }), + google.maps.event.addListener(me.marker_.getMap(), "mousemove", function (mEvent) { + let position; + if (cMouseIsDown) { + if (cDraggingLabel) { + // Change the reported location from the mouse position to the marker position: + mEvent.latLng = new google.maps.LatLng(mEvent.latLng.lat() - cLatOffset, mEvent.latLng.lng() - cLngOffset); + position = me.getProjection().fromLatLngToDivPixel(mEvent.latLng); + if (cRaiseEnabled) { + me.crossDiv_.style.left = position.x + "px"; + me.crossDiv_.style.top = position.y + "px"; + me.crossDiv_.style.display = ""; + position.y -= cRaiseOffset; + } + me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position)); + if (cRaiseEnabled) { // Don't raise the veil; this hack needed to make MSIE act properly + me.eventDiv_.style.top = (position.y + cRaiseOffset) + "px"; + } + google.maps.event.trigger(me.marker_, "drag", mEvent); + } else { + // Calculate offsets from the click point to the marker position: + cLatOffset = mEvent.latLng.lat() - me.marker_.getPosition().lat(); + cLngOffset = mEvent.latLng.lng() - me.marker_.getPosition().lng(); + cSavedZIndex = me.marker_.getZIndex(); + cStartPosition = me.marker_.getPosition(); + cStartCenter = me.marker_.getMap().getCenter(); + cRaiseEnabled = me.marker_.get("raiseOnDrag"); + cDraggingLabel = true; + me.marker_.setZIndex(1000000); // Moves the marker & label to the foreground during a drag + mEvent.latLng = me.marker_.getPosition(); + google.maps.event.trigger(me.marker_, "dragstart", mEvent); + } + } + }), + google.maps.event.addDomListener(document, "keydown", function (e) { + if (cDraggingLabel) { + if (e.keyCode === 27) { // Esc key + cRaiseEnabled = false; + me.marker_.setPosition(cStartPosition); + me.marker_.getMap().setCenter(cStartCenter); + google.maps.event.trigger(document, "mouseup", e); + } + } + }), + google.maps.event.addDomListener(this.eventDiv_, "click", function (e) { + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + if (cIgnoreClick) { // Ignore the click reported when a label drag ends + cIgnoreClick = false; + } else { + google.maps.event.trigger(me.marker_, "click", e); + cAbortEvent(e); // Prevent click from being passed on to map + } + } + }), + google.maps.event.addDomListener(this.eventDiv_, "dblclick", function (e) { + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + google.maps.event.trigger(me.marker_, "dblclick", e); + cAbortEvent(e); // Prevent map zoom when double-clicking on a label + } + }), + google.maps.event.addListener(this.marker_, "dragstart", function (mEvent) { + if (!cDraggingLabel) { + cRaiseEnabled = this.get("raiseOnDrag"); + } + }), + google.maps.event.addListener(this.marker_, "drag", function (mEvent) { + if (!cDraggingLabel) { + if (cRaiseEnabled) { + me.setPosition(cRaiseOffset); + // During a drag, the marker's z-index is temporarily set to 1000000 to + // ensure it appears above all other markers. Also set the label's z-index + // to 1000000 (plus or minus 1 depending on whether the label is supposed + // to be above or below the marker). + me.labelDiv_.style.zIndex = 1000000 + (this.get("labelInBackground") ? -1 : +1); + } + } + }), + google.maps.event.addListener(this.marker_, "dragend", function (mEvent) { + if (!cDraggingLabel) { + if (cRaiseEnabled) { + me.setPosition(0); // Also restores z-index of label + } + } + }), + google.maps.event.addListener(this.marker_, "position_changed", function () { + me.setPosition(); + }), + google.maps.event.addListener(this.marker_, "zindex_changed", function () { + me.setZIndex(); + }), + google.maps.event.addListener(this.marker_, "visible_changed", function () { + me.setVisible(); + }), + google.maps.event.addListener(this.marker_, "labelvisible_changed", function () { + me.setVisible(); + }), + google.maps.event.addListener(this.marker_, "title_changed", function () { + me.setTitle(); + }), + google.maps.event.addListener(this.marker_, "labelcontent_changed", function () { + me.setContent(); + }), + google.maps.event.addListener(this.marker_, "labelanchor_changed", function () { + me.setAnchor(); + }), + google.maps.event.addListener(this.marker_, "labelclass_changed", function () { + me.setStyles(); + }), + google.maps.event.addListener(this.marker_, "labelstyle_changed", function () { + me.setStyles(); + }) + ]; +}; + +/** + * Removes the DIV for the label from the DOM. It also removes all event handlers. + * This method is called automatically when the marker's setMap(null) + * method is called. + * @private + */ +MarkerLabel_.prototype.onRemove = function () { + let i; + this.labelDiv_.parentNode.removeChild(this.labelDiv_); + this.eventDiv_.parentNode.removeChild(this.eventDiv_); + + // Remove event listeners: + for (i = 0; i < this.listeners_.length; i++) { + google.maps.event.removeListener(this.listeners_[i]); + } +}; + +/** + * Draws the label on the map. + * @private + */ +MarkerLabel_.prototype.draw = function () { + this.setContent(); + this.setTitle(); + this.setStyles(); +}; + +/** + * Sets the content of the label. + * The content can be plain text or an HTML DOM node. + * @private + */ +MarkerLabel_.prototype.setContent = function () { + let content = this.marker_.get("labelContent"); + if (typeof content.nodeType === "undefined") { + this.labelDiv_.innerHTML = content; + this.eventDiv_.innerHTML = this.labelDiv_.innerHTML; + } else { + this.labelDiv_.innerHTML = ""; // Remove current content + this.labelDiv_.appendChild(content); + content = content.cloneNode(true); + this.eventDiv_.appendChild(content); + } +}; + +/** + * Sets the content of the tool tip for the label. It is + * always set to be the same as for the marker itself. + * @private + */ +MarkerLabel_.prototype.setTitle = function () { + this.eventDiv_.title = this.marker_.getTitle() || ""; +}; + +/** + * Sets the style of the label by setting the style sheet and applying + * other specific styles requested. + * @private + */ +MarkerLabel_.prototype.setStyles = function () { + let i, labelStyle; + + // Apply style values from the style sheet defined in the labelClass parameter: + this.labelDiv_.className = this.marker_.get("labelClass"); + this.eventDiv_.className = this.labelDiv_.className; + + // Clear existing inline style values: + this.labelDiv_.style.cssText = ""; + this.eventDiv_.style.cssText = ""; + // Apply style values defined in the labelStyle parameter: + labelStyle = this.marker_.get("labelStyle"); + for (i in labelStyle) { + if (labelStyle.hasOwnProperty(i)) { + this.labelDiv_.style[i] = labelStyle[i]; + this.eventDiv_.style[i] = labelStyle[i]; + } + } + this.setMandatoryStyles(); +}; + +/** + * Sets the mandatory styles to the DIV representing the label as well as to the + * associated event DIV. This includes setting the DIV position, z-index, and visibility. + * @private + */ +MarkerLabel_.prototype.setMandatoryStyles = function () { + this.labelDiv_.style.position = "absolute"; + this.labelDiv_.style.overflow = "hidden"; + // Make sure the opacity setting causes the desired effect on MSIE: + if (typeof this.labelDiv_.style.opacity !== "undefined" && this.labelDiv_.style.opacity !== "") { + this.labelDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")\""; + this.labelDiv_.style.filter = "alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")"; + } + + this.eventDiv_.style.position = this.labelDiv_.style.position; + this.eventDiv_.style.overflow = this.labelDiv_.style.overflow; + this.eventDiv_.style.opacity = 0.01; // Don't use 0; DIV won't be clickable on MSIE + this.eventDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=1)\""; + this.eventDiv_.style.filter = "alpha(opacity=1)"; // For MSIE + + this.setAnchor(); + this.setPosition(); // This also updates z-index, if necessary. + this.setVisible(); +}; + +/** + * Sets the anchor point of the label. + * @private + */ +MarkerLabel_.prototype.setAnchor = function () { + let anchor = this.marker_.get("labelAnchor"); + this.labelDiv_.style.marginLeft = -anchor.x + "px"; + this.labelDiv_.style.marginTop = -anchor.y + "px"; + this.eventDiv_.style.marginLeft = -anchor.x + "px"; + this.eventDiv_.style.marginTop = -anchor.y + "px"; +}; + +/** + * Sets the position of the label. The z-index is also updated, if necessary. + * @private + */ +MarkerLabel_.prototype.setPosition = function (yOffset) { + let position = this.getProjection().fromLatLngToDivPixel(this.marker_.getPosition()); + if (typeof yOffset === "undefined") { + yOffset = 0; + } + this.labelDiv_.style.left = Math.round(position.x) + "px"; + this.labelDiv_.style.top = Math.round(position.y - yOffset) + "px"; + this.eventDiv_.style.left = this.labelDiv_.style.left; + this.eventDiv_.style.top = this.labelDiv_.style.top; + + this.setZIndex(); +}; + +/** + * Sets the z-index of the label. If the marker's z-index property has not been defined, the z-index + * of the label is set to the vertical coordinate of the label. This is in keeping with the default + * stacking order for Google Maps: markers to the south are in front of markers to the north. + * @private + */ +MarkerLabel_.prototype.setZIndex = function () { + let zAdjust = (this.marker_.get("labelInBackground") ? -1 : +1); + if (typeof this.marker_.getZIndex() === "undefined") { + this.labelDiv_.style.zIndex = parseInt(this.labelDiv_.style.top, 10) + zAdjust; + this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex; + } else { + this.labelDiv_.style.zIndex = this.marker_.getZIndex() + zAdjust; + this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex; + } +}; + +/** + * Sets the visibility of the label. The label is visible only if the marker itself is + * visible (i.e., its visible property is true) and the labelVisible property is true. + * @private + */ +MarkerLabel_.prototype.setVisible = function () { + if (this.marker_.get("labelVisible")) { + this.labelDiv_.style.display = this.marker_.getVisible() ? "block" : "none"; + } else { + this.labelDiv_.style.display = "none"; + } + this.eventDiv_.style.display = this.labelDiv_.style.display; +}; + +/** + * @name MarkerWithLabelOptions + * @class This class represents the optional parameter passed to the {@link MarkerWithLabel} constructor. + * The properties available are the same as for google.maps.Marker with the addition + * of the properties listed below. To change any of these additional properties after the labeled + * marker has been created, call google.maps.Marker.set(propertyName, propertyValue). + *

+ * When any of these properties changes, a property changed event is fired. The names of these + * events are derived from the name of the property and are of the form propertyname_changed. + * For example, if the content of the label changes, a labelcontent_changed event + * is fired. + *

+ * @property {string|Node} [labelContent] The content of the label (plain text or an HTML DOM node). + * @property {Point} [labelAnchor] By default, a label is drawn with its anchor point at (0,0) so + * that its top left corner is positioned at the anchor point of the associated marker. Use this + * property to change the anchor point of the label. For example, to center a 50px-wide label + * beneath a marker, specify a labelAnchor of google.maps.Point(25, 0). + * (Note: x-values increase to the right and y-values increase to the top.) + * @property {string} [labelClass] The name of the CSS class defining the styles for the label. + * Note that style values for position, overflow, top, + * left, zIndex, display, marginLeft, and + * marginTop are ignored; these styles are for internal use only. + * @property {Object} [labelStyle] An object literal whose properties define specific CSS + * style values to be applied to the label. Style values defined here override those that may + * be defined in the labelClass style sheet. If this property is changed after the + * label has been created, all previously set styles (except those defined in the style sheet) + * are removed from the label before the new style values are applied. + * Note that style values for position, overflow, top, + * left, zIndex, display, marginLeft, and + * marginTop are ignored; these styles are for internal use only. + * @property {boolean} [labelInBackground] A flag indicating whether a label that overlaps its + * associated marker should appear in the background (i.e., in a plane below the marker). + * The default is false, which causes the label to appear in the foreground. + * @property {boolean} [labelVisible] A flag indicating whether the label is to be visible. + * The default is true. Note that even if labelVisible is + * true, the label will not be visible unless the associated marker is also + * visible (i.e., unless the marker's visible property is true). + * @property {boolean} [raiseOnDrag] A flag indicating whether the label and marker are to be + * raised when the marker is dragged. The default is true. If a draggable marker is + * being created and a version of Google Maps API earlier than V3.3 is being used, this property + * must be set to false. + * @property {boolean} [optimized] A flag indicating whether rendering is to be optimized for the + * marker. Important: The optimized rendering technique is not supported by MarkerWithLabel, + * so the value of this parameter is always forced to false. + * @property {string} [crossImage="http://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png"] + * The URL of the cross image to be displayed while dragging a marker. + * @property {string} [handCursor="http://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur"] + * The URL of the cursor to be displayed while dragging a marker. + */ +/** + * Creates a MarkerWithLabel with the options specified in {@link MarkerWithLabelOptions}. + * @constructor + * @param {MarkerWithLabelOptions} [opt_options] The optional parameters. + */ +function MarkerWithLabel(opt_options) { + opt_options = opt_options || {}; + opt_options.labelContent = opt_options.labelContent || ""; + opt_options.labelAnchor = opt_options.labelAnchor || new google.maps.Point(0, 0); + opt_options.labelClass = opt_options.labelClass || "markerLabels"; + opt_options.labelStyle = opt_options.labelStyle || {}; + opt_options.labelInBackground = opt_options.labelInBackground || false; + if (typeof opt_options.labelVisible === "undefined") { + opt_options.labelVisible = true; + } + if (typeof opt_options.raiseOnDrag === "undefined") { + opt_options.raiseOnDrag = true; + } + if (typeof opt_options.clickable === "undefined") { + opt_options.clickable = true; + } + if (typeof opt_options.draggable === "undefined") { + opt_options.draggable = false; + } + if (typeof opt_options.optimized === "undefined") { + opt_options.optimized = false; + } + opt_options.crossImage = opt_options.crossImage || "http" + (document.location.protocol === "https:" ? "s" : "") + "://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png"; + opt_options.handCursor = opt_options.handCursor || "http" + (document.location.protocol === "https:" ? "s" : "") + "://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur"; + opt_options.optimized = false; // Optimized rendering is not supported + + this.label = new MarkerLabel_(this, opt_options.crossImage, opt_options.handCursor); // Bind the label to the marker + + // Call the parent constructor. It calls Marker.setValues to initialize, so all + // the new parameters are conveniently saved and can be accessed with get/set. + // Marker.set triggers a property changed event (called "propertyname_changed") + // that the marker label listens for in order to react to state changes. + google.maps.Marker.apply(this, arguments); +} +inherits(MarkerWithLabel, google.maps.Marker); + +/** + * Overrides the standard Marker setMap function. + * @param {Map} theMap The map to which the marker is to be added. + * @private + */ +MarkerWithLabel.prototype.setMap = function (theMap) { + + // Call the inherited function... + google.maps.Marker.prototype.setMap.apply(this, arguments); + + // ... then deal with the label: + this.label.setMap(theMap); +}; + +module.exports = MarkerWithLabel; diff --git a/src/client/markers/vehicleanimation.js b/src/client/markers/vehicleanimation.js new file mode 100644 index 0000000..57b501e --- /dev/null +++ b/src/client/markers/vehicleanimation.js @@ -0,0 +1,312 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +/* +Draws the individual vehicle history markers and provides functions to animate them. +*/ + +const helpers = require('../../common/helpers'); +const tomiles = require('../tomiles'); +const Status = require('../../common/status'); +const m = require('mithril'); +const TheMap = require('../map'); +const toGoogle = require('../togoogle'); +const MarkerWithLabel = require('./markerWithLabel'); +const ClickListenerFactory = require('./clicklistenerfactory'); +const appState = require('../appState.js'); + +const store = appState.getStore(); + +let i = 0; +let paused = false; +let playing = false; +let lines = []; +let markersById = {}; + +let playPromise, history, progressEl, speed = 0, _controller; + +function create (item) { + let position = toGoogle(item); + if (!position) { + console.warn('Invalid vehicle position ' + JSON.stringify(item)); + return; + } + + let icon = Status.getMarkerIconIndividualHistory(item); + + let marker = new google.maps.Marker({ + position: position, + map: TheMap.getMap(), + title: item.name + }); + + if (icon == null) { + marker.setVisible(false); // hide moving markers + } else { + marker.setIcon(icon); + } + // markers.push(marker); + markersById[item.id] = marker; + + google.maps.event.addListener(marker, 'click', ClickListenerFactory.create(marker, item, position)); + + return marker; +} + +module.exports.clickMarkerByID = function (id) { + new google.maps.event.trigger(markersById[id], 'click'); +} + +let lastState = require('../appDefaultState'); + +store.subscribe(function () { + TheMap.getReady().then(function () { + let state = store.getState(); + + // let lastSelectedVehicle = lastState.selectedVehicle; + // let lastStateVehicleStatusByID = lastState.vehicleStatusByID; + // let vid = state.selectedVehicle ? state.selectedVehicle.id : ''; + // + // if (lastSelectedVehicle === state.selectedVehicle && + // lastStateVehicleStatusByID[vid] === state.vehicleStatusByID[vid] + // ) { + // return; + // } + + let lastSelectedVehicle = lastState.selectedVehicle || {}; + let lastSelectedVehicleHistory = lastState.selectedVehicleHistory; + + lastState = state; + + if (lastSelectedVehicle === state.selectedVehicle) { + // if we're looking at the same vehicle, but not autoupdating the map, don't do anything + if (!state.autoUpdate) { + return; + } else if (lastSelectedVehicleHistory === lastState.selectedVehicleHistory) { + return; + } + } + + if (lastSelectedVehicle !== state.selectedVehicle || + lastSelectedVehicleHistory !== state.selectedVehicleHistory + ) { + // need to clear old markers + _.toArray(markersById).forEach(function (marker) { + marker.setMap(null); + }); + + lines.forEach(function (line) { + line.setMap(null); + }); + + lines = []; + markersById = {}; + + paused = false; + playing = false; + } + + + if (state.selectedVehicle != null) { + let vehicleHistory = state.selectedVehicleHistory; + if (vehicleHistory && vehicleHistory.length) { + history = helpers.addStartStop( + // helpers.rollup( + helpers.cleanData( + // helpers.onlyVisibleHistory( + _.cloneDeep(vehicleHistory))); + // history = history.filter(function (item) { + // return Status.getStatus(item) === 'Sensor Motion'; + // }) + drawAll(); + } else { + stop(); + } + } + }) +}) + +function controller(ctrl) { + if (ctrl != null) { + _controller = ctrl; + } else { + return _controller; + } +}; +module.exports.controller = controller; + +// set the progress element +function progress (el) { + progressEl = el; +}; +module.exports.progress = progress; + +// function history (hist) { +// history = helpers.addStartStop(helpers.rollup(helpers.cleanData(_.cloneDeep(hist)))); +// }; +// module.exports.history = history; + +function animateFrame (i) { + if (progressEl) { + progressEl.value = i; + } + let next = toGoogle(history[i]); + + if (!next) { + console.warn('Vehicle animation frame ' + i + ', invalid position ' + JSON.stringify(next)); + return; + } + + let prev; + let flightPlanCoordinates; + if (i > 0) { + prev = toGoogle(history[i - 1]); + flightPlanCoordinates = [prev, next]; + } + + if (next) { + TheMap.getMap().setCenter(next); + } else { + TheMap.getMap().setCenter(prev); + } + let speed = tomiles(history[i].s); + let color = Status.getStatusColor(history[i]); + + create(history[i], controller()); + + let lineSymbol = { + path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW + }; + + if (flightPlanCoordinates && flightPlanCoordinates.length == 2 && flightPlanCoordinates[0] != null && flightPlanCoordinates[1] != null) { + lines.push(new google.maps.Polyline({ + path: flightPlanCoordinates, + // https://developers.google.com/maps/documentation/javascript/examples/overlay-symbol-arrow + // icons: [{ + // icon: lineSymbol, + // offset: '50%' + // }], + geodesic: true, + strokeColor: color, + strokeOpacity: 0.8, + strokeWeight: 3, + // position: loc, + map: TheMap.getMap(), + // title: i + '' + })); + } +}; +module.exports.animateFrame = animateFrame; + +function stop () { + // if (playPromise) { + // try { + // playPromise.cancel(); + // } catch (e) { + // console.error(e); + // } + // } + + _.toArray(markersById).forEach(function(marker) { + marker.setMap(null); + }) + lines.forEach(function (line) { + line.setMap(null); + }); + + if (progressEl) { + progressEl.value = 0; + + if (history && history.length) { + progressEl.max = history.length - 1; + } + } + + i = 0 + playPromise = Promise.resolve(true); + paused = false; + playing = false; +}; +module.exports.stop = stop; + +function play () { + if (playing === false) { + stop(); + } + paused = false; + playing = true; + nextAnimation(); +} +module.exports.play = play; + +function pause () { + paused = true +} +module.exports.pause = pause; + +function isPausable () { + return playing && !paused; +} +module.exports.isPausable = isPausable; + +function isPlayable() { + return !playing || paused; +} +module.exports.isPlayable = isPlayable; + +function isStoppable() { + return playing || paused; +} +module.exports.isStoppable = isStoppable; + +function drawAll() { + stop(); + let x = 0; + for (; x < history.length; x++) { + animateFrame(x); + } + fitBounds(); +} +module.exports.drawAll = drawAll; + +function nextAnimation() { + if (speed === 0) { + return drawAll(); + } else { + playPromise = playPromise.then(function() { + if (i < history.length) { + return Promise.delay(speed).then(function() { + if (!paused && playing) { + animateFrame(i); + if (i === history.length - 1) { + playing = false; + paused = false; + } else { + i += 1; + nextAnimation(); + } + } + }) + } + }); + } +} + +module.exports.nextAnimation = nextAnimation; + +function setSpeed(value) { + speed = parseInt(value, 10); +} +module.exports.setSpeed = setSpeed; + +function fitBounds() { + let latlngbounds = new google.maps.LatLngBounds(); + + history.forEach(function(item) { + let segment = toGoogle(item); + if (segment) { + latlngbounds.extend(segment) + } + }) + TheMap.getMap().fitBounds(latlngbounds); +} +module.exports.fitBounds = fitBounds; diff --git a/src/client/navbar.js b/src/client/navbar.js new file mode 100644 index 0000000..3fd625f --- /dev/null +++ b/src/client/navbar.js @@ -0,0 +1,324 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState'; +import moment from 'moment'; +import xcloud from './svg/xcloud.js'; +const isUserMetric = require('./isUserMetric'); + +module.exports.controller = function (args, extras) { + const ctrl = this; + + ctrl.manageOpen = m.prop(false); + ctrl.toggleManageOpen = function () { + ctrl.manageOpen(!ctrl.manageOpen()); + } + + ctrl.adminToolsOpen = m.prop(false); + ctrl.adminDropDownConfig = function (el, intialized) { + ctrl.adminDropDownConfigEl = el; + } + ctrl.toggleAdminToolsOpen = function () { + ctrl.adminToolsOpen(!ctrl.adminToolsOpen()); + } + // const anywhereClick = function (e) { + // // todo + // if (!e.target === ctrl.adminDropDownConfigEl) { + // // && !e.target.contains(ctrl.adminDropDownConfigEl)) { + // ctrl.adminToolsOpen(false); + // m.redraw(); + // } + // } + // document.body.addEventListener('click', anywhereClick); + // + // ctrl.onunload = function() { + // document.body.removeEventListener('click', anywhereClick); + // } +} + +module.exports.view = function(ctrl, args, extras) { + const state = appState.getState(); + const view = state.view; + const subview = state.subview; + + function isAdmin() { + return state.user.isAdmin; + } + + function isLoggedIn() { + return state.user.id != null; + } + + function getLoginString() { + const name = state.user.username; + if (name != null) { + return t('Logout', {name: name}); + } else { + return t('Login'); + } + } + + function getWelcomeText() { + if (!!state.user.firstname) { + return t('Welcome', {name: state.user.firstname}); + } else if (!!state.user.username) { + return t('Welcome', {name: state.user.username}); + } + } + + function getOrgName() { + if (state.selectedOrg) { + return state.selectedOrg.name; + } else { + return ''; + } + } + + function orgPresent() { + return state.selectedOrg && state.selectedOrg.id != null; + } + + function lastUpdated() { + if (!state.lastUpdated) { + return ''; + } + if (isUserMetric()) { + return moment(state.lastUpdated).format('HH:mm:ss'); + } else { + return moment(state.lastUpdated).format('h:mm:ss A'); + } + } + + const noConnectivity = !state.realTimeUpdates && state.user.username; + + const svgW = 16; + const svgH = 16; + + function getLogo() { + return m('img[src=images/logosmall.png]') + } + + // state.realTimeUpdates = false; // for testing network failure + + return m('div.container-fluid', [ + m('div.container-fluid', [ + m('li', { + style: { + float: 'left' + } + }, + getLogo() + ), + + m('li.nav navbar-right', { + style: { + 'text-align': 'right' + } + }, [ + + m('a', [m('br'), m('span.company-name', getOrgName()), m('br'), getWelcomeText()]), + m('br'), + noConnectivity ? xcloud() : null, + m('a', { + style: { + 'color': noConnectivity ? 'red' : '' + } + }, (noConnectivity ? t('Connectivity lost') : '') + t('Last update') + ' ' + lastUpdated()), + + ]), + ]), + + m('ul.nav navbar-nav', [ + !orgPresent() ? '' : m('li', { + class: subview === 'REPORT' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewReports(); + } + }, require('./svg/report')(svgW, svgH), t('Reports'))), + + !orgPresent() ? '' : m('li.middle', { + class: subview === 'MAP' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewMap(); + } + }, require('./svg/map')(svgW, svgH), t('Map'))), + + !orgPresent() ? '' : m('li', { + class: subview === 'SPLIT' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewSplitScreen(); + } + }, m('span', { + style: { + color: 'white' + } + }, require('./svg/globe-placeholder')(svgW, svgH)), t('Split Screen'))), + + // TODO add locations. + // !rgPresent() ? '' : m('li', { + // class: routes[2] === orgid && routes[3] === 'locations' ? 'active' : '' + // }, m('a', { + // href: '/organizations/' + orgid + '/locations', + // config: m.route + // }, require('./svg/directionsigns')(svgW, svgH), ' Locations')) + // + ]), + m('ul.nav navbar-nav navbar-right', [ + + !isAdmin() ? '' : m('li', { + class: view === 'ORG' && subview === 'ALL' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewOrganizations(); + } + }, orgPresent() ? t('Back to Organizations') : t('Organizations'))), + + isAdmin() && !orgPresent() ? m('li', { + class: view === 'USER' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewUsers(); + } + }, t('Users'))) : '', + + isAdmin() && !orgPresent() ? m('li', { + class: view === 'DEVICE' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewDevices(); + } + }, t('Devices'))) : '', + + isAdmin() && !orgPresent() ? m('li.dropdown.pointer', { + class: ctrl.adminToolsOpen() ? 'open' : '', + onclick: ctrl.toggleAdminToolsOpen, + config: ctrl.adminDropDownConfig + },[ + m('a.dropdown-toggle', t('Messages'), m('span.caret')), + m('ul.dropdown-menu', [ + isAdmin() ? m('li', { + class: state.view === 'EVENTS' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewEvents(); + } + }, t('Processed Messages'))) : '', + + isAdmin() ? m('li', { + class: state.view === 'RAWEVENTS' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewRawEvents(); + } + }, t('Raw Messages'))) : '', + + isAdmin() ? m('li', { + class: state.view === 'EXCEPTIONS' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewExceptions(); + } + }, t('Uncaught Exceptions'))) : '', + ]) + ]) : '', + + !orgPresent() ? '' : m('li.dropdown.pointer', { + class: ctrl.manageOpen() ? 'open' : '', + onclick: ctrl.toggleManageOpen + },[ + m('a.dropdown-toggle', t('Manage'), m('span.caret')), + m('ul.dropdown-menu', [ + !orgPresent() ? '' : m('li', { + class: subview === 'USERS' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewOrgUsers(); + } + }, t('Users'))), + + !orgPresent() ? '' : m('li', { + class: subview === 'FLEETS' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewOrgFleets(); + } + }, t('Fleets'))), + + !orgPresent() ? '' : m('li', { + class: subview === 'VEHICLES' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewOrgVehicles(); + } + }, t('Vehicles'))), + + // !orgPresent() ? '' : m('li', { + // class: view === ''ALERTS'' ? 'active' : '' + // }, m('a', { + // onclick: function () { + // appState.viewAlerts(); + // } + // }, t('Alerts'))), + ]) + ]), + + !orgPresent() ? '' : m('li', { + class: view === 'PROFILE' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewUserByID(state.user.username); + } + }, t('Profile'))), + + !orgPresent() ? '' : m('li', { + class: view === 'HELP' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewHelp(); + } + }, t('Help'))), + + m('li', { + class: view === 'SESSION' ? 'active' : '' + }, m('a', { + href: '#', + onclick: function (ev) { + ev.preventDefault(); + appState.viewLogin(); + } + }, t('Log Out'))) + ]) + ]); +}; diff --git a/src/client/organization-new.js b/src/client/organization-new.js new file mode 100644 index 0000000..a69dee9 --- /dev/null +++ b/src/client/organization-new.js @@ -0,0 +1,106 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState'; +const Device = require('../common/models/Device'); +const catchhandler = require('./catchhandler'); +const Organization = require('../common/models/Organization'); +const _ = require('lodash'); +const keyhelper = require('./keyhelper'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + const state = appState.getState(); + ctrl.org = new Organization(state.orgsByID[state.viewID]); + + if (state.orgsByID[state.viewID]) { + ctrl.editing = true; + } else { + ctrl.editing = false; + ctrl.org = new Organization(); + ctrl.org.id = state.viewID; + } + + // appState.getStore().subscribe(function () { + // const state = appState.getState(); + // if (state.orgsByID[ctrl.org.id]) { + // ctrl.org = state.orgsByID[ctrl.org.id]; + // m.redraw(); + // } + // }) +}; + +module.exports.view = function(ctrl) { + const org = ctrl.org; + const editing = ctrl.editing; + + return m('div', [ + m('.col-sm-3'), + m('.business-table col-sm-6 ', [ + m('.btn.center', editing ? t('Edit Organization') : t('Create Organization')), + m('form.form-horizontal', [ + Object.keys(org).map(function (key) { + return m('div.form-group', [m('label.col-md-2 control-label', t(keyhelper(key)) + ':'), m('div.col-md-10', m('input.form-control', { + onchange: function (ev) { + org[key] = ev.target.value; + }, + disabled: key === 'id', + value: org[key] + }))]) + }) + // m('div.form-group', [m('label.col-md-2 control-label', 'Name'), m('div.col-md-10 ', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.organization.name), + // value: ctrl.organization.name() + // }))]), + // m('div.form-group', [m('label.col-md-2 control-label', 'EIN'), m('div.col-md-10 ', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.organization.ein), + // value: ctrl.organization.ein() + // }))]), + // m('div.form-group', [m('label.col-md-2 control-label', 'Address Line 1'), m('div.col-md-10 ', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.organization.address1), + // value: ctrl.organization.address1() + // }))]), + // m('div.form-group', [m('label.col-md-2 control-label', 'Address Line 2'), m('div.col-md-10 ', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.organization.address2), + // value: ctrl.organization.address2() + // }))]), + // m('div.form-group', [m('label.col-md-2 control-label', 'City'), m('div.col-md-10 ', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.organization.name), + // value: ctrl.organization.city() + // }))]), + // m('div.form-group', [m('label.col-md-2 control-label', 'State'), m('div.col-md-10 ', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.organization.tate), + // value: ctrl.organization.state() + // }))]), + // m('div.form-group', [m('label.col-md-2 control-label', 'Zip'), m('div.col-md-10 ', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.organization.zip), + // value: ctrl.organization.zip() + // }))]), + // m('div.form-group', [m('label.col-md-2 control-label', 'Country'), m('div.col-md-10 ', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.organization.country), + // value: ctrl.organization.country() + // }))]) + ]), + m('.buttons-right', [ + m('button.btn btn-default', { + onclick: function (e) { + window.history.back(); + } + }, t('Cancel')), + ' ', + m('button.btn btn-success', { + onclick: function () { + appState.saveOrg(org) + .then(function () { + window.history.back(); + }) + .catch(catchhandler); + } + }, t('Save')) + ]) + + ]), + m('.col-sm-3') + ]) +}; diff --git a/src/client/organization.js b/src/client/organization.js new file mode 100644 index 0000000..f197b2b --- /dev/null +++ b/src/client/organization.js @@ -0,0 +1,205 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; + +const m = require('mithril'); +const _ = require('lodash'); +const navbar = require('./navbar'); +const users = require('./users') +const Status = require('../common/status'); +const todir = require('../common/todir'); +const helpers = require('../common/helpers'); +const tzOffset = require('./tzoffset'); +const tomiles = require('./tomiles'); +const hidenan = require('../common/hidenan'); +const toGoogle = require('./togoogle'); +const sorts = require('./sorts'); +const reports = require('./reports/reports'); +const street = require('../common/addressdisplay').street; +const city = require('../common/addressdisplay').city; +const stateFormat = require('../common/addressdisplay').state; +const appState = require('./appState'); +const OrgMarkers = require('./markers/OrgMarkers'); +const ClickListenerFactory = require('./markers/clicklistenerfactory'); +const formatDate = require('./formatDate'); +const isUserMetric = require('./isUserMetric'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + ctrl.selectedItem = m.prop({}); + + ctrl.clickItem = function(item) { + if (ctrl.selectedItem() === item) { + ctrl.selectedItem({}); + ClickListenerFactory.closeInfoWindow(); + } else { + ctrl.selectedItem(item); + OrgMarkers.clickMarkerByVehicleID(item.id); + } + } +}; + +module.exports.view = function(ctrl, args, extras) { + const state = appState.getState(); + + const advancedUI = state.user.advancedMode; + + let refreshLater = null; + const RECENTLY_CHANGED = 10000; /// was updated 10 seconds ago + function wasRecentlyUpdated(date) { + date = new Date(date); + const lastUpdated = new Date() - date < RECENTLY_CHANGED; + if (lastUpdated && refreshLater == null) { + refreshLater = Promise.delay(RECENTLY_CHANGED).then(function () { + // queue a redraw for later to remove highlights from recently updated history items. + m.redraw(); + }) + } + return lastUpdated; + } + + return m('.business-table', [ + // m('button.btn btn-primary btn-xs btn-pad', { + // onclick: function () { + // appState.update(); + // } + // }, 'Update'), + // ' ', + m('label', { + style: { + 'margin-right': '.5em' + } + }, + m('input[type=checkbox]', { + // checked: ctrl.autoUpdate(), + checked: state.autoUpdate, + onclick: function() { + appState.setAutoUpdate(this.checked); + }, + }), + t('Auto Update Map')), + ' ', + // + // m('span', 'Last event: '), + // m('span.padrt.updated-border', (!state.lastUpdated ? '' : moment(state.lastUpdated).format('h:mm:ss A'))), + + m('label.padrt', m('input[type=checkbox]', { + onclick: function() { + appState.setShowVerbose(this.checked); + }, + checked: state.verbose + }), t('Verbose')), + + m('label.padrt', m('input[type=checkbox]', { + onclick: function() { + appState.setShowLatLong(this.checked); + }, + checked: state.showLatLong + }), t('LAT/LONG')), + + m('a.padrt', { + href: '/api/organizations/' + state.selectedOrg.id + '/vehiclestatus?format=excel' + + '&latlong=' + state.showLatLong + + '&verbose=' + state.verbose + + '&tzOffset=' + encodeURIComponent(tzOffset()), + style: { + cursor: 'pointer', + } + }, m('img', { + src: 'images/excel-icon.png', + }), ' ' + t('Excel')), + + m('br'), + m('label', 'Total: ' + state.impliedSelectedVehicles.length), + m('table.table.table-bordered.table-striped', sorts(state.impliedSelectedVehicles), [ + m('thead', { + style: { + cursor: 'pointer' + } + }, [ + m('td[data-sort-by=name]', t('Name')), + m('td[data-sort-by=last.d]', t('Date')), + m('td', t('Address')), + m('td', t('City')), + m('td', t('State')), + !state.verbose ? '' : m('td[data-sort-by=last.m]', t('Odometer')), + !state.verbose ? '' : m('td[data-sort-by=last.h]', t('Hour Meter')), + m('td[data-sort-by=azimuth(last)]', t('Dir')), + m('td[data-sort-by=last.s]', isUserMetric() ? t('km/h') : t('mph')), + state.showLatLong ? m('td[data-sort-by=last.la]', t('Lat')) : '', + state.showLatLong ? m('td[data-sort-by=last.lo]', t('Long')) : '', + m('td[data-sort-by=Status.getStatus(last)]', t('Status')), + !state.verbose ? '' : m('td[data-sort-by=last.b]', t('Online')), + !state.verbose ? '' : m('td[data-sort-by=last.bp]', t('Battery')), + m('td[data-sort-by=last.g]', t('GPS')) + ]), + m('tbody', { + style: { + cursor: 'pointer' + } + }, + + state.impliedSelectedVehicles.map(function(vehicle) { + if (!vehicle) { + throw new TypeError('Null vehicle'); + } + + let lastStatus; + if (state.verbose) { + if (vehicle.lastVerbose && vehicle.last) { + if (new Date(vehicle.lastVerbose.d) >= new Date(vehicle.last.d)) { + lastStatus = vehicle.lastVerbose; + } else { + lastStatus = vehicle.last; + } + } else if (vehicle.lastVerbose) { + lastStatus = vehicle.lastVerbose; + } else if (vehicle.last) { + lastStatus = vehicle.last; + } + } else if (vehicle.last) { + lastStatus = helpers.cleanItem(vehicle.last); + } + + if (!lastStatus) { + return m('tr', [ + m('td.nowrap', vehicle.name), + ]); + } + + return m('tr', { + id: vehicle.id, + key: vehicle.id, + onclick: function(ev) { + ctrl.clickItem(vehicle); + }, + style: { + 'transition': wasRecentlyUpdated(lastStatus.d) ? 'background-color 1s ease-in-out' : 'none', + 'background-color': vehicle.id === ctrl.selectedItem().id ? '#FEE0C6' + : wasRecentlyUpdated(lastStatus.d) ? 'yellow' : '' + } + }, [ + m('td.nowrap', vehicle.name), + m('td.nowrap', lastStatus.d ? formatDate(lastStatus.d) : ''), + m('td.nowrap', street(lastStatus)), + m('td.nowrap', city(lastStatus)), + m('td.nowrap', stateFormat(lastStatus)), + !state.verbose ? '' : m('td.nowrap', hidenan(tomiles(lastStatus.m))), + !state.verbose ? '' : m('td.nowrap', lastStatus.h), + m('td.nowrap', todir(lastStatus)), + m('td.nowrap', hidenan(tomiles(lastStatus.s))), + state.showLatLong ? m('td.nowrap', lastStatus.la) : '', + state.showLatLong ? m('td.nowrap', lastStatus.lo) : '', + m('td.nowrap', { + style: { + color: Status.getStatusColor(lastStatus) + } + }, t(Status.getStatus(lastStatus))), + !state.verbose ? '' : m('td.nowrap', lastStatus.b ? t('Buffered') : t('Yes')), + !state.verbose ? '' : m('td.nowrap', lastStatus.bp ? lastStatus.bp + '%' : ''), + m('td.nowrap', helpers.getAccuracyAsImg(lastStatus.g)) + ]) + })) + ]) + ]) +}; diff --git a/src/client/organizations.js b/src/client/organizations.js new file mode 100644 index 0000000..227503f --- /dev/null +++ b/src/client/organizations.js @@ -0,0 +1,80 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState'; +const navbar = require('./navbar'); +const catchhandler = require('./catchhandler'); +const withAuth = require('./withAuth'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + + ctrl.delete = function (org) { + let result = window.confirm('Are you sure you want to delete organization ' + org.name + '?'); + + if (result === true) { + appState.deleteOrg(org) + .catch(catchhandler); + } + } +}; + +module.exports.view = function(ctrl) { + const state = appState.getState(); + const isAdmin = state.user.isAdmin; + + return m('.div', [ + m('.col-md-2'), + m('.business-table col-md-8', { + // class: !isAdmin ? 'col-sm-4' : 'col-sm-9' + }, [!isAdmin ? '' : m('button.btn btn-default', { + style: { + 'margin-bottom': '1em' + }, + onclick: function () { + appState.viewNewOrganization(); + } + }, t('Create Organization')), + m('table.table table-bordered table-striped', [ + m('thead', + m('tr', [ + m('th', t('Name')), + m('th', ''), + m('th', ''), + m('th', '') + ]) + ), + m('tbody', [ + _.toArray(state.orgsByID).map(function(org) { + return m('tr', [m('td', org.name), + m('td', + ' ', !isAdmin ? '' : m('a.btn btn-primary btn-sm', { + onclick: function (ev) { + appState.editOrganization(org.id); + }, + }, m('span.middle glyphicon glyphicon-pencil'), ' ' + t('Update'))), + + m('td', m('a.btn btn-primary btn-sm', { + onclick: function (ev) { + appState.selectOrgByID(org.id) + .then(function () { + appState.viewOrgByID(org.id); + }); + }, + }, m('span.middle glyphicon glyphicon-search'), ' ' + t('Log In'))), + + m('td', m('a.btn btn-primary btn-sm', { + onclick: function(ev) { + ev.preventDefault(); + ctrl.delete(org) + } + }, m('span.middle glyphicon glyphicon-trash'), ' ' + t('Delete'))) + ]) + }) + ]) + ]) + ]), + m('.col-md-3') + ]) +}; diff --git a/src/client/orgselector.js b/src/client/orgselector.js new file mode 100644 index 0000000..3370887 --- /dev/null +++ b/src/client/orgselector.js @@ -0,0 +1,31 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const m = require('mithril'); +const key = 'orgid'; +const _ = require('lodash'); + +const appState = require('./appState'); + +module.exports = function (obj, col1, col2) { + const state = appState.getState(); + + if (!obj.orgid) { + obj.orgid = state.selectedOrg.id; + } + + col1 = col1 || 2; + col2 = col2 || 10; + + if (state.user.isAdmin) { + return m('div.form-group', [m('label.col-md-'+col1+' control-label', 'Organization:'), m('div.col-md-'+col2, m('select.form-control', { + onchange: function (ev) { + obj[key] = ev.target.value; + }, + value: obj[key] || state.selectedOrg.id + }, _.union([{id:' '}], _.toArray(state.orgsByID)).map(function (org) { + return m('option', { + value: org.id + }, org.name); + })))]) + } +} diff --git a/src/client/reports/daily.js b/src/client/reports/daily.js new file mode 100644 index 0000000..ce46ba3 --- /dev/null +++ b/src/client/reports/daily.js @@ -0,0 +1,68 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const m = require('mithril'); +const tohms = require('./tohms'); +const tomiles = require('../tomiles'); +const _ = require('lodash'); +const isUserMetric = require('../isUserMetric'); +const formatDate = require('../formatDate'); + +module.exports.view = function (ctrl, args, extras) { + + if (!(args.result() && args.result().vehicles && args.result().results)) { + return ''; + } + + return m('div', [ + m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('Date')), + m('td', t('First Ign On')), + m('td', t('Last Ign Off')), + m('td', t('Duration')), + m('td', t('Begin Odometer')), + m('td', t('End Odometer')), + m('td', isUserMetric() ? t('Kilometers') : t('Miles')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return args.result().results[vid].length > 0 ? [ + m('tr', m('td[colspan=7].group', args.result().vehicles[vid].name)), + _.map(args.result().results[vid], function(result) { + return m('tr', [ + m('td', formatDate(result.d)), + m('td', result.firstIgnOn ? formatDate(result.firstIgnOn) : ''), + m('td', result.lastIgnOff ? formatDate(result.lastIgnOff) : ''), + m('td', tohms(result.duration)), + m('td', tomiles(result.beginOdometer)), + m('td', tomiles(result.endOdometer)), + m('td', tomiles(result.distance)) + ]) + }) + ] : '' + })) + ]) + ]), + + // m('br'), + // + // args.result() && args.result().vehicles ? m('div', [ + // // m('h3', 'Totals'), + // m('table.table-condensed table-bordered table-striped dataTable', [ + // m('thead', [ + // m('td', 'Vehicle'), + // m('td', 'Total Durations'), + // m('td', 'Total Miles') + // ]), + // m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + // return m('tr', [ + // m('td', args.result().vehicles[vid].name), + // m('td', tohms(args.result().totals[vid])), + // m('td', tohms(args.result().totals[vid])) + // ]) + // })) + // ]) + // ]) : '', + ]); +} diff --git a/src/client/reports/idle.js b/src/client/reports/idle.js new file mode 100644 index 0000000..654ae39 --- /dev/null +++ b/src/client/reports/idle.js @@ -0,0 +1,69 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const m = require('mithril'); +const moment = require('moment'); +const tohms = require('./tohms'); +const street = require('../../common/addressdisplay').street; +const city = require('../../common/addressdisplay').city; +const state = require('../../common/addressdisplay').state; +const _ = require('lodash'); +const isUserMetric = require('../isUserMetric'); +const formatDate = require('../formatDate'); + +// need location, city, state, idleStart, idleEnd, duration +//total: vehicle, idling total +module.exports.view = function(ctrl, args, extras) { + + if (!(args.result() && args.result().vehicles && args.result().results)) { + return ''; + } + return m('div', [ + args.result() && args.result().vehicles ? m('div', [ + // m('h3', 'Totals'), + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('Vehicle')), + m('td', t('Idling Total')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return m('tr', [ + m('td', args.result().vehicles[vid].name), + m('td', tohms(args.result().totals[vid] / 1000)) + ]) + })) + ]) + ]) : '', + + m('br'), + + m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('Location')), + m('td', t('City')), + m('td', t('State')), + m('td', t('Idle Start')), + m('td', t('Idle End')), + m('td', t('Duration')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return args.result().results[vid].length > 0 ? [ + m('tr', m('td[colspan=6].group', args.result().vehicles[vid].name)), + _.map(args.result().results[vid], function(result) { + return m('tr', [ + m('td', street(result)), + m('td', city(result)), + m('td', state(result)), + m('td', formatDate(result.d)), + m('td', formatDate(moment(result.d).add(result.idleTime / 1000, 'seconds'))), + m('td', tohms(result.idleTime / 1000)) + ]) + }) + ] : '' + })) + ]) + ]), + + ]); +} diff --git a/src/client/reports/ignition.js b/src/client/reports/ignition.js new file mode 100644 index 0000000..da9af7b --- /dev/null +++ b/src/client/reports/ignition.js @@ -0,0 +1,54 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const m = require('mithril'); +const tomiles = require('../tomiles'); +const Status = require('../../common/status'); +const tohms = require('./tohms'); +// const street = require('../../common/addressdisplay').street; +const full = require('../../common/addressdisplay').full; +const isUserMetric = require('../isUserMetric'); +const formatDate = require('../formatDate'); + +const _ = require('lodash'); + +module.exports.view = function(ctrl, args, extras) { + + if (!(args.result() && args.result().vehicles && args.result().results)) { + return ''; + } + + return m('div', [ + m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('Ign On')), + m('td', t('Ign Off')), + m('td', t('Ignition On Time')), + m('td', isUserMetric() ? t('Kilometers') : t('Miles')), + m('td', t('Parked @')), + m('td', t('Parked Until')), + m('td', t('Parked Time')), + m('td', t('Idle Time')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return [ + m('tr', m('td[colspan=8].group', args.result().vehicles[vid].name)), + args.result().results[vid].map(function(item) { + return m('tr', [ + m('td', item.startTime ? formatDate(item.startTime) : ''), + m('td', formatDate(item.d)), + m('td', item.transitTime ? tohms(item.transitTime) : ''), + m('td', tomiles(item.startStopMileage)), + m('td', full(item)), + m('td', item.parkedEnd ? formatDate(item.parkedEnd) : ''), + m('td', item.parkedDuration ? tohms(item.parkedDuration) : ''), + m('td', item.idleDuration ? tohms(item.idleDuration) : '') + ]) + }) + ] + })) + ]) + ]), + ]); +} diff --git a/src/client/reports/jes.js b/src/client/reports/jes.js new file mode 100644 index 0000000..5a77b49 --- /dev/null +++ b/src/client/reports/jes.js @@ -0,0 +1,65 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const toMiles = require('../tomiles'); +const m = require('mithril'); +const tohms = require('./tohms'); +const street = require('../../common/addressdisplay').street; +const city = require('../../common/addressdisplay').city; +const state = require('../../common/addressdisplay').state; +const _ = require('lodash'); +const formatDate = require('../formatDate'); + +// need location, city, state, idleStart, idleEnd, duration +//total: vehicle, idling total +module.exports.view = function(ctrl, args, extras) { + + if (!(args.result() && args.result().vehicles && args.result().results)) { + return ''; + } + return m('div', [ + m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('Date')), + m('td', t('Location')), + m('td', t('City')), + m('td', t('State')), + m('td', t('RPM max')), + m('td', t('RPM avg')), + m('td', t('Throttle max')), + m('td', t('Throttle avg')), + m('td', t('Engine Load max')), + m('td', t('Engine Load avg')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return args.result().results[vid].length > 0 ? [ + m('tr', m('td[colspan=18].group', args.result().vehicles[vid].name)), + _.map(args.result().results[vid], function(result) { + if (!result.obd) { + result.obd = Object.create(null); + } + + if (!result.obd.diagnosticTroubleCodes) { + result.obd.diagnosticTroubleCodes = []; + } + + return m('tr', [ + m('td', formatDate(result.d)), + m('td', street(result)), + m('td', city(result)), + m('td', state(result)), + m('td', _.get(result, 'jes.maxRPM')), + m('td', _.get(result, 'jes.averageRPM')), + m('td', _.get(result, 'jes.maxThrottlePosition')), + m('td', _.get(result, 'jes.averageThrottlePosition')), + m('td', _.get(result, 'jes.maxEngineLoad')), + m('td', _.get(result, 'jes.averageEngineLoad')) + ]) + }) + ] : '' + })) + ]) + ]), + ]); +} diff --git a/src/client/reports/mileage.js b/src/client/reports/mileage.js new file mode 100644 index 0000000..47c444e --- /dev/null +++ b/src/client/reports/mileage.js @@ -0,0 +1,58 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const m = require('mithril'); +const moment = require('moment'); +const tohms = require('./tohms'); +const street = require('../../common/addressdisplay').street; +const city = require('../../common/addressdisplay').city; +const state = require('../../common/addressdisplay').state; +const tomiles = require('../tomiles'); +const _ = require('lodash'); +const isUserMetric = require('../isUserMetric'); + +module.exports.view = function(ctrl, args, extras) { + + if (!(args.result() && args.result().vehicles && args.result().results)) { + return ''; + } + + return m('div', [ + m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('State')), + m('td', isUserMetric() ? t('Kilometers') : t('Miles')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return [ + m('tr', m('td[colspan=7].group', args.result().vehicles[vid].name)), + Object.keys(args.result().results[vid]).map( function(key) { + return m('tr', [ + m('td', key), + m('td', tomiles(args.result().results[vid][key])) + ]) + }) + ] + })) + ]) + ]), + + m('br'), + + args.result() && args.result().vehicles ? m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('State')), + m('td', isUserMetric() ? t('Kilometers') : t('Miles')) + ]), + m('tbody', _.map(Object.keys(args.result().totals), function(key) { + return m('tr', [ + m('td', key), + m('td', tomiles(args.result().totals[key])) + ]) + })) + ]) + ]) : '', + ]); +} diff --git a/src/client/reports/obd.js b/src/client/reports/obd.js new file mode 100644 index 0000000..adb5819 --- /dev/null +++ b/src/client/reports/obd.js @@ -0,0 +1,91 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const toMiles = require('../tomiles'); +const m = require('mithril'); +const tohms = require('./tohms'); +const street = require('../../common/addressdisplay').street; +const city = require('../../common/addressdisplay').city; +const state = require('../../common/addressdisplay').state; +const _ = require('lodash'); +const isUserMetric = require('../isUserMetric'); +const formatDate = require('../formatDate'); + +// need location, city, state, idleStart, idleEnd, duration +//total: vehicle, idling total +module.exports.view = function(ctrl, args, extras) { + + if (!(args.result() && args.result().vehicles && args.result().results)) { + return ''; + } + return m('div', [ + m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('Date')), + m('td', t('Location')), + m('td', t('City')), + m('td', t('State')), + m('td', t('Conn')), + m('td', '⚠'), + m('td', t('Codes')), + m('td', t('Temp')), + m('td', t('Fuel')), + m('td', t('Load')), + m('td', t('ThrtlPos')), + m('td', t('RPMs')), + m('td', t('Fuel Cnsmp')), + m('td', t('PIDs')), + m('td', t('Speed')), + m('td', t('Power')), + m('td', t('VIN')), + m('td', isUserMetric() ? t('OBD Kilometers') : t('OBD Mileage')), + m('td', isUserMetric() ? t('Kilometers') : t('Miles')), + // m('td', 'OBD-II Data') + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return args.result().results[vid].length > 0 ? [ + m('tr', m('td[colspan=19].group', args.result().vehicles[vid].name)), + _.map(args.result().results[vid], function(result) { + if (!result.obd) { + result.obd = Object.create(null); + } + + if (!result.obd.diagnosticTroubleCodes) { + result.obd.diagnosticTroubleCodes = []; + } + + return m('tr', [ + m('td', formatDate(result.d)), + m('td', street(result)), + m('td', city(result)), + m('td', state(result)), + m('td', result.obd.connect ? '✓' : ''), + m('td', result.obd.malfunction ? result.obd.diagnosticTroubleCodes.length + '⚠' : ''), + m('td', result.obd.diagnosticTroubleCodes.map(function (code) { + return [m('a', { + href: 'http://www.obd-codes.com/p' + code, + target: '_new' + }, code), ' ']; + })), + m('td', (result.obd.temp ? result.obd.temp + '℃' : '')), + m('td', result.obd.fuelLevelInput ? result.obd.fuelLevelInput + '%' : ''), + m('td', result.obd.engineLoad), + m('td', result.obd.throttlePosition), + m('td', result.obd.RPMs), + m('td', result.obd.fuelConsumption), + m('td', result.obd.supportPIDs), + m('td', toMiles(result.obd.speed)), + m('td', result.obd.powermV ? result.obd.powermV /1000 + 'V' : ''), + m('td', result.obd.vin), + m('td', toMiles(result.obd.mileage)), + m('td', toMiles(result.m)) + // m('pre', JSON.stringify(result.obd, null, 4)) + ]) + }) + ] : '' + })) + ]) + ]), + ]); +} diff --git a/src/client/reports/odometer.js b/src/client/reports/odometer.js new file mode 100644 index 0000000..72c75af --- /dev/null +++ b/src/client/reports/odometer.js @@ -0,0 +1,45 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const m = require('mithril'); +const tohms = require('./tohms'); +const street = require('../../common/addressdisplay').street; +const city = require('../../common/addressdisplay').city; +const state = require('../../common/addressdisplay').state; +const tomiles = require('../tomiles'); +const _ = require('lodash'); +const isUserMetric = require('../isUserMetric'); +const formatDate = require('../formatDate'); + +module.exports.view = function(ctrl, args, extras) { + + if (!(args.result() && args.result().vehicles && args.result().results)) { + return ''; + } + + return m('div', [ + m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('State')), + m('td', isUserMetric() ? t('Kilometers') : t('Miles')), + m('td', t('Start Odometer')), + m('td', t('End Odometer')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return [ + m('tr', m('td[colspan=7].group', args.result().vehicles[vid].name)), + args.result().results[vid].map(function(item) { + return m('tr', [ + m('td', item.state), + m('td', tomiles(item.odometerEnd - item.odometerStart)), + m('td', tomiles(item.odometerStart)), + m('td', tomiles(item.odometerEnd)), + ]) + }) + ] + })) + ]) + ]), + ]); +} diff --git a/src/client/reports/reports.js b/src/client/reports/reports.js new file mode 100644 index 0000000..9e6d487 --- /dev/null +++ b/src/client/reports/reports.js @@ -0,0 +1,305 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; + +const m = require('mithril'); +const navbar = require('../navbar'); +// const DatePicker = require('sm-datepicker'); +const moment = require('moment'); +const types = require('../../common/report/types'); +const tzOffset = require('../tzoffset'); +const pikaday = require('pikaday2').default; + +const idle = require('./idle'); +const daily = require('./daily'); +const mileage = require('./mileage'); +const odometer = require('./odometer'); +const speed = require('./speed'); +const ignition = require('./ignition'); +const start = require('./start'); +const summary = require('./summary'); +const obd = require('./obd'); +const jes = require('./jes'); +const _ = require('lodash'); +const withAuth = require('../withAuth'); + +const appState = require('../appState'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + + ctrl.executing = false; + ctrl.error = null; + + ctrl.result = m.prop({ + query: { + vehicles: [] + }, + results: {}, + totals: {} + }); + + ctrl.reportName = m.prop('idle'); + ctrl.startDate = m.prop(moment().startOf('day').toDate()); + ctrl.endDate = m.prop(moment().startOf('day').toDate()); + + ctrl.dateRangeChange = function(ev) { + if (ev === 'Today') { + ctrl.startDatePicker.setDate(moment().startOf('day').add(1, 'days').format('YYYY-MM-DD')); + ctrl.endDatePicker.setDate(moment().startOf('day').add(1, 'days').format('YYYY-MM-DD')); + } + if (ev === 'Yesterday') { + ctrl.startDatePicker.setDate(moment().startOf('day').format('YYYY-MM-DD')); + ctrl.endDatePicker.setDate(moment().startOf('day').add(0, 'days').format('YYYY-MM-DD')); + } + if (ev === 'Last 2 Days') { + ctrl.startDatePicker.setDate(moment().startOf('day').subtract(0, 'days').format('YYYY-MM-DD')); + ctrl.endDatePicker.setDate(moment().startOf('day').add(1, 'days').format('YYYY-MM-DD')); + } + if (ev === 'Last 3 Days') { + ctrl.startDatePicker.setDate(moment().startOf('day').subtract(1, 'days').format('YYYY-MM-DD')); + ctrl.endDatePicker.setDate(moment().startOf('day').add(1, 'days').format('YYYY-MM-DD')); + } + if (ev === 'This week to date') { + ctrl.startDatePicker.setDate(moment().startOf('day').subtract(7, 'days').format('YYYY-MM-DD')); + ctrl.endDatePicker.setDate(moment().startOf('day').add(1, 'days').format('YYYY-MM-DD')); + } + if (ev === 'Last week') { + ctrl.startDatePicker.setDate(moment().startOf('day').subtract(1, 'week').format('YYYY-MM-DD')); + ctrl.endDatePicker.setDate(moment().startOf('day').format('YYYY-MM-DD')); + } + if (ev === 'This month') { + ctrl.startDatePicker.setDate(moment().startOf('month').add(1, 'days').format('YYYY-MM-DD')); + ctrl.endDatePicker.setDate(moment().startOf('month').add(1, 'month').add(0, 'days').format('YYYY-MM-DD')); + } + if (ev === 'Last month') { + ctrl.startDatePicker.setDate(moment().startOf('month').subtract(1, 'month').add(1, 'days').format('YYYY-MM-DD')); + ctrl.endDatePicker.setDate(moment().startOf('month').add(0, 'days').format('YYYY-MM-DD')); + } + } + + ctrl.run = function() { + ctrl.result({}); + ctrl.executing = true; + ctrl.error = null; + m.redraw(); + + const state = appState.getState(); + const IDs = []; + state.impliedSelectedVehicles.forEach(function (vehicle) { + IDs.push(vehicle.id); + }); + + m.request({ + url: '/api/organizations/' + + state.selectedOrg.id + + '/reports/' + + encodeURIComponent(ctrl.reportName()) + + '?vehicles=' + + encodeURIComponent(JSON.stringify(IDs)) + + '&startDate=' + encodeURIComponent(ctrl.startDate().toISOString()) + + '&endDate=' + encodeURIComponent(moment(ctrl.endDate()).add(1, 'day').toISOString()) + // + // + '&startDate=' + encodeURIComponent(state.startDate.toISOString()) + // + '&endDate=' + encodeURIComponent(moment(state.startDate).add(1, 'day').toISOString()) + + '&tzOffset=' + encodeURIComponent(tzOffset()), + config: withAuth + }) + .then(function(results) { + ctrl.result(results); + ctrl.executing = false; + }) + .catch(function (err) { + ctrl.executing = false; + ctrl.error = err; + throw err; + }) + } +}; + +module.exports.view = function(ctrl, args, extras) { + return m('.div', [ + m('div.business-table', + m('.row', [ + m('div.col-md-12', { + style: { + 'margin-top': '1em', + 'margin-bottom': '1em' + } + }, [ + m('span', t('Quick select') + ' '), + m('span.button-group', [ + m('button.btn btn-default', { + onclick: function () { + this.blur(); + ctrl.dateRangeChange('Today'); + } + }, t('Today')), + + m('button.btn btn-default', { + onclick: function () { + this.blur(); + ctrl.dateRangeChange('Yesterday'); + } + }, t('Yesterday')), + + m('button.btn btn-default', { + onclick: function () { + this.blur(); + ctrl.dateRangeChange('Last 2 Days'); + } + }, t('Last 2 Days')), + + m('button.btn btn-default', { + onclick: function () { + this.blur(); + ctrl.dateRangeChange('Last 3 Days'); + } + }, t('Last 3 Days')), + + // m('button.btn btn-default', { + // onclick: function () { + // this.blur(); + // ctrl.dateRangeChange('This week to date'); + // } + // }, t('This week to date')), + + m('button.btn btn-default', { + onclick: function () { + this.blur(); + ctrl.dateRangeChange('Last week'); + } + }, t('Last week')), + + m('button.btn btn-default', { + onclick: function () { + this.blur(); + ctrl.dateRangeChange('This month'); + } + }, t('Last month')), + + // m('button.btn btn-default', { + // onclick: function () { + // this.blur(); + // ctrl.dateRangeChange('Last month'); + // } + // }, t('This month')) + ]) + ]), + m('div.col-md-12', { + style: { + 'margin-top': '1em', + 'margin-bottom': '1em' + } + }, [ + m('label.padrt', t('Start Date')), + m('span.padrt', { + config: function(el, isInitialized) { + if (isInitialized) + return; + const input = document.createElement('input'); + el.appendChild(input); + + ctrl.startDatePicker = new pikaday({ + defaultDate: ctrl.startDate(), + setDefaultDate: true, + field: input, + onSelect: function() { + ctrl.startDate(this.getDate()); + m.redraw(); + } + }); + }, + }), + m('label.padrt', t('End Date')), + m('span', { + config: function(el, isInitialized) { + if (isInitialized) + return; + const input = document.createElement('input'); + el.appendChild(input); + + ctrl.endDatePicker = new pikaday({ + defaultDate: ctrl.endDate(), + setDefaultDate: true, + field: input, + onSelect: function() { + ctrl.endDate(this.getDate()); + m.redraw(); + } + }); + }, + }) + ]), + m('div.col-md-3', m('select.form-control', { + size: Object.keys(types).length, + onchange: m.withAttr('value', ctrl.reportName), + }, + Object.keys(types).map(function(key) { + return m('option', { + value: key, + selected: key === ctrl.reportName() + }, t(types[key])) + }) + ), m('button.btn btn-default btn-success', { + style: { + 'margin-top': '1em', + 'margin-bottom': '1em' + }, + disabled: ctrl.executing, + onclick: ctrl.run + }, ctrl.executing ? t('Executing...') : t('Run!'))), + + m('.row.col-md-12', [ + + ctrl.result().query && ctrl.result().query.reportid === 'idle' ? m.component(idle, { + result: ctrl.result, + }) : '', + + ctrl.result().query && ctrl.result().query.reportid === 'daily' ? m.component(daily, { + result: ctrl.result, + }) : '', + + ctrl.result().query && ctrl.result().query.reportid === 'mileage' ? m.component(mileage, { + result: ctrl.result, + }) : '', + + ctrl.result().query && ctrl.result().query.reportid === 'odometer' ? m.component(odometer, { + result: ctrl.result, + }) : '', + + ctrl.result().query && ctrl.result().query.reportid === 'speed' ? m.component(speed, { + result: ctrl.result, + }) : '', + + ctrl.result().query && ctrl.result().query.reportid === 'ignition' ? m.component(ignition, { + result: ctrl.result, + }) : '', + + ctrl.result().query && ctrl.result().query.reportid === 'start' ? m.component(start, { + result: ctrl.result, + }) : '', + + ctrl.result().query && ctrl.result().query.reportid === 'summary' ? m.component(summary, { + result: ctrl.result, + }) : '', + + ctrl.result().query && ctrl.result().query.reportid === 'obd' ? m.component(obd, { + result: ctrl.result, + }) : '', + + ctrl.result().query && ctrl.result().query.reportid === 'jes' ? m.component(jes, { + result: ctrl.result, + }) : '', + // ,m('div.business-table', [ + // m('pre', JSON.stringify(ctrl.result(), undefined, 4)) + // ]) + + ctrl.error ? m('div.business-table', [ + m('pre', JSON.stringify(ctrl.error, undefined, 4)) + ]) : null + ]) + ]) + ) + ]) +}; diff --git a/src/client/reports/speed.js b/src/client/reports/speed.js new file mode 100644 index 0000000..76848e6 --- /dev/null +++ b/src/client/reports/speed.js @@ -0,0 +1,78 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const m = require('mithril'); +const tomiles = require('../tomiles'); +const todir = require('../../common/todir'); +const street = require('../../common/addressdisplay').street; +const city = require('../../common/addressdisplay').city; +const state = require('../../common/addressdisplay').state; +const _ = require('lodash'); +const isUserMetric = require('../isUserMetric'); +const formatDate = require('../formatDate'); + +function renderLocation(item) { + let res = ''; + if (street(item) !== '') { + res = res + street(item); + } + if (city(item) !== '') { + res = res + ', ' + city(item); + } + if (state(item) !== '') { + res = res + ', ' + state(item); + } + return res; +} + +module.exports.view = function(ctrl, args, extras) { + + if (!(args.result() && args.result().vehicles && args.result().results)) { + return ''; + } + + return m('div', [ + args.result() && args.result().vehicles ? m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', 'Vehicle'), + m('td', 'Highest ' + (isUserMetric() ? t('km/h') : t('mph'))) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + if (_.isFinite(tomiles(args.result().totals[vid]))) { + return m('tr', [ + m('td', args.result().vehicles[vid].name), + m('td', tomiles(args.result().totals[vid])) + ]) + } + })) + ]) + ]) : '', + + m('br'), + + m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('Location')), + m('td', t('Date')), + m('td', t('Heading')), + m('td', isUserMetric() ? t('km/h') : t('mph')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return [ + m('tr', m('td[colspan=7].group', args.result().vehicles[vid].name)), + args.result().results[vid].map(function(item) { + return m('tr', [ + m('td', renderLocation(item)), + m('td', formatDate(item.d)), + m('td', todir(item)), + m('td', tomiles(item.s)) + ]) + }) + ] + })) + ]) + ]) + ]); +} diff --git a/src/client/reports/start.js b/src/client/reports/start.js new file mode 100644 index 0000000..36b7d89 --- /dev/null +++ b/src/client/reports/start.js @@ -0,0 +1,53 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const m = require('mithril'); +const tomiles = require('../tomiles'); +const Status = require('../../common/status'); +const tohms = require('./tohms'); +// const street = require('../../common/addressdisplay').street; +const full = require('../../common/addressdisplay').full; +const _ = require('lodash'); +const isUserMetric = require('../isUserMetric'); +const formatDate = require('../formatDate'); + +module.exports.view = function(ctrl, args, extras) { + + if (!(args.result() && args.result().vehicles && args.result().results)) { + return ''; + } + + return m('div', [ + m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', [ + m('thead', [ + m('td', t('Started Moving')), + m('td', t('Stopped Moving')), + m('td', t('Transit Time')), + m('td', isUserMetric() ? t('Kilometers') : t('Miles')), + m('td', t('Parked @')), + m('td', t('Parked Until')), + m('td', t('Parked Time')), + m('td', t('Idle Time')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return [ + m('tr', m('td[colspan=8].group', args.result().vehicles[vid].name)), + args.result().results[vid].map(function(item) { + return m('tr', [ + m('td', item.startTime ? formatDate(item.startTime) : ''), + m('td', formatDate(item.d)), + m('td', item.transitTime ? tohms(item.transitTime) : ''), + m('td', tomiles(item.startStopMileage)), + m('td', full(item)), + m('td', item.parkedEnd ? formatDate(item.parkedEnd) : ''), + m('td', item.parkedDuration ? tohms(item.parkedDuration) : ''), + m('td', item.idleDuration ? tohms(item.idleDuration) : '') + ]) + }) + ] + })) + ]) + ]), + ]); +} diff --git a/src/client/reports/summary.js b/src/client/reports/summary.js new file mode 100644 index 0000000..0bc674c --- /dev/null +++ b/src/client/reports/summary.js @@ -0,0 +1,49 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from '../i18n'; +const m = require('mithril'); +const moment = require('moment'); +const tohms = require('./tohms'); +const tomiles = require('../tomiles'); +const _ = require('lodash'); +const isUserMetric = require('../isUserMetric'); + +module.exports.view = function(ctrl, args, extras) { + if (!(args.result() && args.result().vehicles && args.result().results)) { + return m('div'); + } + + return m('div', m('div', [ + m('table.table-condensed table-bordered table-striped dataTable', + m('thead', [ + m('td', t('Vehicle')), + m('td', t('Transit Time')), + m('td', isUserMetric() ? t('Kilometers') : t('Miles')), + m('td', t('Parked Time')), + m('td', t('Parked')), + m('td', t('Avg Park')), + m('td', t('Total Idling')), + m('td', t('Idle')), + m('td', t('Avg Idle Time')), + m('td', t('Begin Odometer')), + m('td', t('End Odometer')) + ]), + m('tbody', _.map(Object.keys(args.result().vehicles), function(vid) { + return m('tr', [ + m('td', args.result().vehicles[vid].name), + m('td', tohms(args.result().results[vid].totalTransit)), + m('td', tomiles(args.result().results[vid].distance)), + m('td', tohms(args.result().results[vid].totalPark)), + m('td', args.result().results[vid].parks), + m('td', tohms(args.result().results[vid].avgPark)), + m('td', tohms(args.result().results[vid].totalIdle)), + m('td', args.result().results[vid].idles), + m('td', tohms(args.result().results[vid].avgIdle)), + m('td', tomiles(args.result().results[vid].beginOdometer)), + m('td', tomiles(args.result().results[vid].endOdometer)) + ]) + })) + ) + ])) + +} diff --git a/src/client/reports/tohms.js b/src/client/reports/tohms.js new file mode 100644 index 0000000..b07fad3 --- /dev/null +++ b/src/client/reports/tohms.js @@ -0,0 +1,32 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const _ = require('lodash'); + +module.exports = function(seconds) { + + if (!_.isFinite(seconds)) { + return ''; + } + + const sec_num = parseInt(seconds, 10); // don't forget the second param + let hours = Math.floor(sec_num / 3600); + const minutes = Math.floor((sec_num % 3600) / 60); + seconds = Math.floor(sec_num % 60); + const days = Math.floor(hours / 24); + + if (hours >= 24) { + hours = hours - days * 24; + } + + // if (hours < 10) { + // hours = "0" + hours; + // } + // if (minutes < 10) { + // minutes = "0" + minutes; + // } + // if (seconds < 10) { + // seconds = "0" + seconds; + // } + const time = (days > 0 ? days + 'd ' : '') + hours + 'h ' + minutes + 'm ' + seconds + 's'; + return time; +} diff --git a/src/client/root.js b/src/client/root.js new file mode 100644 index 0000000..6e45d36 --- /dev/null +++ b/src/client/root.js @@ -0,0 +1,227 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const m = require('mithril'); +const navbar = require('./navbar'); +const TheMap = require('./map'); +const session = require('./session'); +const organizations = require('./organizations'); +const organization = require('./organization'); +const neworganization = require('./organization-new'); +const users = require('./users'); +const user = require('./user'); +const newuser = require('./user-new'); +const vehicles = require('./vehicles'); +const vehicle = require('./vehicle'); +const newvehicle = require('./vehicle-new'); +const devices = require('./devices'); +const newdevice = require('./device-new'); +const events = require('./events'); +const reports = require('./reports/reports'); +const alerts = require('./alerts'); +const locations = require('./locations'); +const fleets = require('./fleets'); +const help = require('./help'); +const sidebar = require('./sidebar'); +const appState = require('./appState'); + +const USER = 'USER'; +const USERS = 'USERS'; +const ORG = 'ORG'; +const ORGS = 'ORGS'; +const DEVICE = 'DEVICE'; +const DEVICES = 'DEVICES'; +const FLEET = 'FLEET'; +const FLEETS = 'FLEETS'; +const VEHICLE = 'VEHICLE'; +const VEHICLES = 'VEHICLES'; + +const NEW = 'NEW'; +const EDIT = 'EDIT'; +const ALL = 'ALL'; + +const SPLIT = 'SPLIT'; +const MAP = 'MAP'; +const REPORT = 'REPORT'; + +const EVENTS = 'EVENTS'; +const RAWEVENTS = 'RAWEVENTS'; +const EXCEPTIONS = 'EXCEPTIONS'; + +const HELP = 'HELP'; +const SESSION = 'SESSION'; + + +module.exports.getMapElement = function () { + return mapElement; +} + +let mapElement = null; + +module.exports.controller = function (args, extras) { + const ctrl = this; + + ctrl.mapVisible = function (visible, tall) { + TheMap.setVisible(visible, tall); + } + + ctrl.mapInitialized = false; + + this.mapElement = function (el, isInitialized) { + if (!isInitialized) { + ctrl.mapInitialized = true; + TheMap.mount(el); + mapElement = el; + } + } +} + +module.exports.view = function (ctrl, args, extras) { + const state = appState.getState(); + const view = state.view; + const subview = state.subview; + + if (view === HELP) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = help; + } else if (view === SESSION) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = session; + } else if (subview === ORG) { + if (view === USER) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = users; + } else if (view === FLEET) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = fleets; + } else if (view === VEHICLE) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = vehicles; + } + + } else + if (view === EVENTS || view === RAWEVENTS || view === EXCEPTIONS) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = m.component(events); + } else if (subview === ALL) { + if (view === ORG) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = organizations; + } + + if (view === USER) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = users; + } + + if (view === DEVICE) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = devices; + } + } else if (view === ORG) { + ctrl.mapVisible(true, false); + + if (subview === REPORT) { + ctrl.reportComponent = reports; + ctrl.mapVisible(false); + } else { + if (state.selectedVehicle) { + ctrl.reportComponent = vehicle; + } else { + ctrl.reportComponent = organization; + } + } + + if (subview === MAP) { + ctrl.mapVisible(true, true); + } + + if (subview === SPLIT) { + ctrl.mapVisible(true, false); + } + ctrl.sidebarComponent = sidebar; + ctrl.mainComponent = null; + + if (subview === EDIT) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = neworganization; + } + + if (subview === NEW ) { + ctrl.mapVisible(false); + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = neworganization; + } + } else if (view === DEVICE) { + ctrl.mapVisible(false); + + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = newdevice; + } else if (view === USER) { + ctrl.mapVisible(false); + + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = newuser; + } else if (view === VEHICLE) { + ctrl.mapVisible(false); + + ctrl.reportComponent = null; + ctrl.sidebarComponent = null; + ctrl.mainComponent = newvehicle; + } else { + ctrl.mapVisible(false); + ctrl.mainComponent = session; + } + + return m('div', [ + m('nav.navbar navbar-static-top navbar-inverse', [ + m.component(navbar) + ]), + m('div.container-fluid', + m('.row', [ + m('div#sidebar.col-sm-2', [ + ctrl.sidebarComponent + ]), + m('.col-sm-10', [ + ctrl.mapInitialized ? { + subtree: 'retain' + } : m('.map shadow', { + style: { + // visibility: 'hidden' + }, + config: ctrl.mapElement, + }), + // report + ctrl.reportComponent + ]) + ]) + ), + m('.container-fluid', [ + m('.row', [ + ctrl.mainComponent + ]) + ]) + ]) +} diff --git a/src/client/session.js b/src/client/session.js new file mode 100644 index 0000000..fc7cc7d --- /dev/null +++ b/src/client/session.js @@ -0,0 +1,158 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +const m = require('mithril'); +const appState = require('./appState'); +const catchhandler = require('./catchhandler'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + const state = appState.getState(); + + ctrl.username = m.prop(state.user.username ? state.user.username : ''); + ctrl.password = m.prop(''); + ctrl.loggingIn = false; + ctrl.rememberMe = m.prop(false); + ctrl.error = m.prop(''); + + const store = require('./appState').getStore(); + + ctrl.loginClick = function() { + ctrl.loggingIn = true; + ctrl.error(''); + m.redraw(); + + appState.login({ + username: ctrl.username().trim(), + password: ctrl.password(), + rememberMe: ctrl.rememberMe() + }) + .then(function() { + ctrl.loggingIn = false; + m.redraw(); + + const state = appState.getState(); + + if (!state.user.isAdmin) { + return appState.viewOrgByID(state.user.orgid); + } else { + return appState.viewOrganizations(); + } + }) + .catch(function(err) { + ctrl.loggingIn = false; + ctrl.error(err.message); + m.redraw(); + }) + }; + + ctrl.logoutClick = function() { + let wantsToLogout = window.confirm(t('Are you sure you wish to logout?')); + if (!wantsToLogout) return; + ctrl.loggingIn = true; + ctrl.error(''); + m.redraw(); + + appState.logOut() + .then(function() { + ctrl.loggingIn = false; + m.redraw(); + }) + .catch(function(err) { + ctrl.loggingIn = false; + ctrl.error(err.message); + }) + }; +}; + +module.exports.view = function(ctrl) { + + const state = appState.getState(); + + function buttonText() { + if (ctrl.loggingIn) { + return t('Authorizing...'); + } else { + return t('Log In'); + } + } + + function getLogo() { + return m('img[src=images/logo2.png]'); + } + return m('div', [ + m('.row center-block', { + style: { + width: '400px', + 'margin-right': '2px', + border: 'solid thin black', + padding: '2em' + } + }, [ + !state.user.username ? m('input.form-control', { + placeholder: t('Username'), + autofocus: true, + oninput: m.withAttr('value', ctrl.username), + onkeyup: function(ev) { + if (ev.keyCode === 13) { + ctrl.loginClick(); + } + }, + value: ctrl.username() + }) : null, + !state.user.username ? m('input.form-control', { + placeholder: t('Password'), + type: 'password', + oninput: m.withAttr('value', ctrl.password), + onkeyup: function(ev) { + if (ev.keyCode === 13) { + ctrl.loginClick(); + } else { + m.redraw.strategy('none'); + } + }, + value: ctrl.password() + }) : null, + + !state.user.username ? m('label', m('input[type=checkbox]', { + checked: ctrl.rememberMe(), + onclick: function() { + ctrl.rememberMe(this.checked); + }, + }), t('Remember Me')) : null, + + m('div', { + style: { + 'text-align': 'right', + 'margin-top': '2px' + } + }, [ + + state.user.username ? m('button.btn btn-default', { + class: ctrl.loggingIn ? '' : 'btn-default', + style: { + 'float': 'left' + }, + onclick: ctrl.logoutClick, + disabled: ctrl.loggingIn, + }, t('Log Out') + ' ' + state.user.username) : null, + + !state.user.username ? m('button.btn btn-default', { + class: ctrl.loggingIn ? '' : 'btn-success', + onclick: ctrl.loginClick, + disabled: ctrl.loggingIn + }, buttonText()) : null, + ]), + m('br'), + m('div.text-danger', ctrl.error() ? ('Error: ' + ctrl.error()) : '') + ]), + m('.row', m('.center-block', { + style: { + 'margin-top': '2em', + 'text-align': 'center', + } + }, + getLogo() + )) + ]) +}; diff --git a/src/client/sidebar.js b/src/client/sidebar.js new file mode 100644 index 0000000..8ca59b9 --- /dev/null +++ b/src/client/sidebar.js @@ -0,0 +1,123 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +const m = require('mithril'); +const _ = require('lodash'); +const appState = require('./appState'); + +module.exports.controller = function (args, extras) { + const ctrl = this; + ctrl.searchInput = m.prop(''); + ctrl.searchInputChange = function (ev) { + ctrl.searchInput(ev.target.value); + } +} + +module.exports.view = function (ctrl, args, extras) { + const state = appState.getState(); + const fleets = _.toArray(state.fleetsByID); + + function formatVehicle(vehicle) { + if (!vehicle) return ''; + let str = ''; + str += vehicle.name; + + // quick testing + // vehicle.obd = { + // malfunction: true, + // diagnosticTroubleCodesCount: 1, + // temp: 95, + // fuelLevelInput: 97, + // } + // vehicle.deviceBatteryPercent = 23; + + if (vehicle.obd) { + const obd = vehicle.obd; + var prev = false; + if (obd.malfunction) { + str += ' '; + if (_.isFinite(obd.diagnosticTroubleCodesCount) && obd.diagnosticTroubleCodesCount > 1) { + str += obd.diagnosticTroubleCodesCount; + } + str += '⚠'; + prev = true; + } + + // if (obd.temp) { + // if (prev) str += " |"; + // str += ' ' + obd.temp + '℃'; + // prev = true; + // } + + if (obd.fuelLevelInput) { + if (prev) str += " |" + if (_.isFinite(obd.fuelLevelInput)) { + str += ' ' + obd.fuelLevelInput + '%⛽'; + } + prev = true; + } + } + + // if (_.isFinite(vehicle.deviceBatteryPercent)) { + // str += ' ' + vehicle.deviceBatteryPercent + '%🔋'; + // } + return str; + } + + return m('div.business-table.fullwidth', [ + m('from.form-search', [ + m('input.input-search.fullwidth', { + onkeyup: ctrl.searchInputChange, + value: ctrl.searchInput() + }), + m('span.middle glyphicon glyphicon-search', { + style: { + position: 'absolute', + right: '45px', + top: '24px' + }, + onclick: function () { + ctrl.searchInput(''); + } + }) + ]), + m('ul.list-group', [ + + // Fleets/All + m('li.pointer list-group-item', { + class: state.selectedAllFleets ? 'active' : '', + onclick: function (ev) { + appState.selectFleetAll(); + } + }, require('./svg/truck-facing')(12, 12), ' '+t('Fleets/All')), + + // Individual Fleets + fleets.map(function (fleet) { + return [ + m('li.pointer list-group-item', { + class: !state.selectedAllFleets && state.selectedFleets.length === 1 && state.selectedFleets[0].id === fleet.id ? 'active' : '', + onclick: function (ev) { + appState.selectFleet(fleet); + } + }, require('./svg/truck')(12, 12, fleet.color), ' ', m('b', fleet.name)), + + fleet.vehicles.filter(function (vid) { + const vehicle = state.vehiclesByID[vid]; + return ctrl.searchInput() === '' || vehicle.name.toUpperCase().indexOf(ctrl.searchInput().toUpperCase()) > -1; + }).map(function (vid) { + const vehicle = state.vehiclesByID[vid]; + return m('li.pointer list-group-item', { + style: { + margin: '0 0 0 15px' + }, + class: state.selectedVehicle && vehicle && state.selectedVehicle.id === vehicle.id ? 'active' : '', + onclick: function (ev) { + appState.selectVehicleByID(vehicle.id); + } + }, formatVehicle(vehicle) ) + }) + ] + }) + ]) + ]) +} diff --git a/src/client/sorts.js b/src/client/sorts.js new file mode 100644 index 0000000..169c991 --- /dev/null +++ b/src/client/sorts.js @@ -0,0 +1,49 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const Status = require('../common/status'); +const todir = require('../common/todir'); + +function getProp(name, obj) { + if (name === 'Status.getStatus(last)') { + return Status.getStatus(obj.last); + } + + if (name === 'azimuth(last)') { + return todir(obj.last); + } + + let prop = name.split('.'); + let i = 0; + while (i < prop.length) { + if (obj != null) { + obj = obj[prop[i]]; + } + i++; + } + return obj; +} + + +function sorts(list) { + return { + onclick: function(e) { + let prop = e.target.getAttribute("data-sort-by") + + if (prop) { + let first = list[0] + list.sort(function(a, b) { + // let x = a[prop]; + // let y = b[prop]; + let x = getProp(prop, a); + let y = getProp(prop, b); + if (x == null) x = ''; + if (y == null) y = ''; + + return x > y ? 1 : x < y ? -1 : 0 + }) + if (first === list[0]) list.reverse() + } + } + } +} +module.exports = sorts; diff --git a/src/client/style.css b/src/client/style.css new file mode 100644 index 0000000..6a16771 --- /dev/null +++ b/src/client/style.css @@ -0,0 +1,336 @@ +* { + box-sizing: border-box; +} + +body { + padding: 0; + height: 100%; + width: 100%; + min-height: 100%; + font-size: 1.2em; + background: #D2D2D2; + min-width: 300px; + position: relative; + font-family: Helvetica, Arial, Sans-Serif; +} + +.sizing-box { + height: 30px; + width: 60px; +} + +.pointer { + cursor: pointer; +} + +.center { + text-align: center; +} + +nav { + z-index: 1 !important; +} + +.navbar { + font-size: 14px; + position: relative; + min-height: 25px; + margin-bottom: 10px; +} + +.nav > li > a { + padding-top: 10px; + padding-bottom: 9px; + line-height: 14px; +} + +.nav > li > a:hover, .nav > li > a:focus { + background-color: #2D5682; + text-decoration: none; + padding-top: 10px; + padding-bottom: 9px; +} + +.active > a { + /*background-color: #337ab7 !important;*/ + /*border-radius: 0px;*/ + /*color: white !important;*/ +} + +.business-table { + padding-top: 1.5em; + padding-left: 2em; + padding-right: 2em; + padding-bottom: 1.5em; + /*background-color: #EEEEEE;*/ + /*background-color: white;*/ + box-shadow: 6px 6px 3px #888888; + background-color: rgb(238, 238, 238); +} + +.list-group-item:first-child { + border-radius: 0; +} + +.list-group-item:last-child { + border-radius: 0; +} +.list-group-item { + background-color: rgb(238, 238, 238); + border: none; + font-size: 12px; +} + +.list-group-item:hover { + border: 1px darkgrey; + font-size: 12px; +} + +.list-group-item.active { + background-color: #B9D5FF; + color: black; +} + +.list-group-item.active:hover { + background-color: #B9D5FF; + border: 1px darkgrey; + color: black; +} + +.shadow { + box-shadow: 6px 6px 3px #888888; + margin-left: 8px; + margin-right: 8px; +} + +.middle { + vertical-align: middle; +} + +thead { + /*background-color: rgb(103, 140, 198);*/ + background-color: #337ab7; + color: white; + text-align: center; + vertical-align: middle; + font-weight: bold; +} + +.map { + margin-bottom: 10px; +} + +.maplabel { + background: white; + padding-left: 2px; + padding-right: 2px; + border: thin solid black; +} + +.buttons-right { + float:right; + bottom: 10px; + right: 10px; + font-size: 12px; +} + +.table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; + font-size: 12px; + border-collapse: collapse; + border-spacing: 0; +} + +.table td { + padding-bottom: 1px !important; + padding-left: 10px !important; + padding-right: 5px !important; + padding-top: 1px !important; + vertical-align: middle; + border-right: 1px solid #3D6895 !important; + border-color: #3D6895 !important; +} + +.table-bordered { + font-size: 12px !important; + border-collapse: collapse; + border: 1px solid #3D6895; +} + +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: white; +} + +.huge { + font-size: 64pt; +} + +.huge:hover { + text-decoration: none; + cursor: pointer; +} + +.nowrap { + white-space: nowrap; +} + +.list-group-item { + padding: 4px 4px; +} + +.fullwidth { + width: 100%; +} + +.verticalcenter { + /*float:none;*/ + display:inline-block; + vertical-align:middle; + margin-right:-4px; +} + +.company-name { + color: #fff; + font-size: 1.2em; + text-transform: uppercase; + font-weight: bold; + text-shadow: 1px 1px 1px #345578; +} + +.nav :hover { + text-decoration: none; +} + +.highlight-igniton { + background-color: rgb(154, 205, 50) !important; +} + +.nowrap { + white-space: nowrap; +} + +.padrt { + margin-right: 1em; +} + +.btn-primary { + color: #ffffff; + background-color: #36618F; + border-color: #36618F; + font-size: 1em; + border-radius: 0; +} + +.updated-border { + border: 1px solid #ccc; + padding: 7px; +} + +.btn-pad { + padding: 3px 3px; +} + +input[type=range] { + /*removes default webkit styles*/ + -webkit-appearance: none; + + /*fix for FF unable to apply focus style bug */ + border: 1px solid white; + + /*required for proper track sizing in FF*/ + width: 300px; +} +input[type=range]::-webkit-slider-runnable-track { + width: 300px; + height: 5px; + background: #ddd; + border: none; + border-radius: 3px; +} +input[type=range]::-webkit-slider-thumb { + -webkit-appearance: none; + border: none; + height: 16px; + width: 16px; + border-radius: 50%; + background: goldenrod; + margin-top: -4px; +} +input[type=range]:focus { + outline: none; +} +input[type=range]:focus::-webkit-slider-runnable-track { + background: #ccc; +} + +input[type=range]::-moz-range-track { + width: 300px; + height: 5px; + background: #ddd; + border: none; + border-radius: 3px; +} +input[type=range]::-moz-range-thumb { + border: none; + height: 16px; + width: 16px; + border-radius: 50%; + background: goldenrod; +} + +/*hide the outline behind the border*/ +input[type=range]:-moz-focusring{ + outline: 1px solid white; + outline-offset: -1px; +} + +input[type=range]::-ms-track { + width: 300px; + height: 5px; + + /*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */ + background: transparent; + + /*leave room for the larger thumb to overflow with a transparent border */ + border-color: transparent; + border-width: 6px 0; + + /*remove default tick marks*/ + color: transparent; +} +input[type=range]::-ms-fill-lower { + background: #777; + border-radius: 10px; +} +input[type=range]::-ms-fill-upper { + background: #ddd; + border-radius: 10px; +} +input[type=range]::-ms-thumb { + border: none; + height: 16px; + width: 16px; + border-radius: 50%; + background: goldenrod; +} +input[type=range]:focus::-ms-fill-lower { + background: #888; +} +input[type=range]:focus::-ms-fill-upper { + background: #ccc; +} + +.fleet-all-link { + background: #B9D5FF; + color: #2D5682; + cursor: pointer !Important; + font-weight: bold; +} + +.group { + background-color: #ffffcc; + text-align: left!important; + font-weight: bold!important; +} diff --git a/src/client/style/Sorting icons.psd b/src/client/style/Sorting icons.psd new file mode 100644 index 0000000000000000000000000000000000000000..53b2e06850767cb57c52b316f0b845b1a8e0ca0e GIT binary patch literal 27490 zcmeG^33yY*)^oGAX}T}$5K3uTx@2jaq_m}N($WHj(w42FkS4cnARAd|!3_{mfhUTH zY|1K#_&`w>abZmhao`qBLJ(pzsNq?Pf|62BSCWcgaLqBHCE&EOUv}>Xi$*(!wu`FiTD>VJ z{+AE7#EbO0ocN&`rQ%YHimuZaPq5Mz69!ajCydc5b@9D(1=$T*4MvNRwrfNUMuW+g z)sPdf(V461EPydOEnY-e>|=7`WvP->Ns2@wjn5T`M51h~t|qHoUF4F4R8D-I-EPTB zORKN1Ppy}wnys~I5~Wg^CYGj2r76IXVjFL=YZ_8awl0hkw;nZZ(^~ZwyWVUPVZEAa zv%{VfACEKgTuc#lT2DR}ht)uG(P`6Y18t;Dc3T=0GR>nLWV3bJtQxb`sIlj2EEa=a ztHHUXjWg*|NmWxVb!NNSR%fGR{uJrSU2qsXEr$0{>^FZqQgf#WvYoIcv?v zG$25c#lA%bWR}WGYwTugrP*xA&BtvbDsvZ9q^gjLhU!f^bGI#2 zx!pT4Hfx|&50)W)DOZx6b{o#C;)FJ=oVJ+_4&3*0B$)~ zF$4*~fLF+prOM1?nOKr6lPDl4lQX0cWKzI^9=R9-@XB#I1LzQB=`v}rf^>;GQ!SAw z)Y8n1LTRB?kzbUNAum)aRbsg$-)&)^lDUfgmyJ<$gZ?glfGM~80mf#P=^JRnFtr}~ zi4C`{M46p-M}n7;o9V;vCg??IDX20V%+?Bc+R@nYh%PTwOKu;F$ubq0>B;G0Wu}JT!^AScXGj>H^kgh0Co!}rv=(3>228plLrh|5O@N^-A%@nM%fL5q4Ezu) zajXDNh;d#r@Dv>5Tx8%uI0jjWi7fa}x+EQ_IEK@OP-$z z*2q+*H+%AKvYtw%9JQGGgG9g;Kq04yQ7|By$z-Xl#URGqDo{%8e~E?WP!UC(Ew}Fc$bb}2q$QFIthf3 zj$(9lAZdI~lu3tr(ha0sZ9M6Yqz;!zI+(-|xwHsK8cv;Jo+Rc}slamzl|>{k6P{v} zR#O8M1H?R+6oXkZZ@vd3C910+cJpKqOiD9`=)4AL1T}_w-RWYV#pF9toX&rThVv#S zL(qzBl49YU5Mu`d60DejTnb-|eQ^zNt?&umFv1f=FxX~*W92cy)f%{M5o&Iowm8YU z0uh#S$zYtxVKBfApYaW<*4XF)8Y5jOPZp!{+B!EKr+GFw4olmH82Z~FMfv2z zB{V=sLEw`_iP}pyzt(DYSbR`CvsDjgk7<*`2r|OL3alN@2?7q%p&EzX+=n*NRyc~P z0|crZZ=qex0)`o5Fr~y;D}vjDu0I>j54#NSGA?c!Ured3*4;P^4^LyTS88f~xWcqF z$k7e<5?gU)Y5!_Cvx}L7+-M)>;5xH)LcT#?>$X%lQ~6>y8YKBTx<=zL*Z~Y4M_cW8 zU?1W}`?7~r*OK!|UdD}N^cVE;5I_VCFq^QggY9O^K!@E%yB!151O{-V+pxlFvmG4j zHhc&)aa{{`(p$P=T}TLl>V1*GOuq^z=wcuh_t%@uEa)3Xlii9>MGYHXCF1Xco*E4O z4*XoBwOL9lig4dRaAHb?k4`a~NDNlKa+K*AU#1k7i9}ws`vD`h7AqK;Dg$Pj4i2FM zJOyAwz1@QGxYRM#V=&CZJub!y1q8S?hHDu(neZ@h9)@*B6Zkg^m)W8->M*<$;Ah7< zu-~)$13Yz{o~{S@Fu(~0hfxnO9v@?jvNSje{dzx|0lFc~tQW#s|S;T&!8CN|Ip^Z-?)cTudT*6|6 z!lxj#VZT>>;;_GXeUU&uJ^8qT-sE%e&`ZO=DCVUBgN$DT z5WV~siW!-TBKF51_Ro6|CprYNN4y3U%F}NBgNGp8^M-ah!}vYGKqs+J#F`07mQ7Ed z3P@F6DbhNu;}{kWzH#Ac9*$yA8`KeXLETUak|H_kh4N4#>Wc=#jB7Z01m;+E$OzBY zdh{5Ygr=hD=mqpLnvWKtPbl{1(iz`QvIoNYB)8Ds-;YngL;g5ikeQ%qUKXes8!TE)ce#nYBzO| z`kFdHouhuEZm`%aAuEQ}ftAQgV<}kqtbVLY*2An?)>zgA))dzBthubEthZPjSld`% zu#T`ASwFEZvk^Ol9mnp>PGKw9D)vBj6}yIQWk125#-77o%3j0X%-+TRlHJHY&%Vy# zaiTdQP70?NrL)6<_+hK<~_=r!F!drmbaC6kavoAna}69;rHa{ z@CWiWd^>+Ce;)rW{ucfr{%QWTppc+WLDHb2psFBK(Bz;wL2m|q9CRq?Owi5Xh~Tcl zS-}H?b;09m|v zT3B>gYFJ5_F6_y$1z{V)4uxF^4-W4do*({5_=NB|;qQj;4?iCf9FZ8IiqJ$n5wRfR z{fJ``mm{MiC6NOojgd1V-;CTHc{Yk4l^9hRrHh&pwJd5!)TwB8beCvVv^M&w=;hI$ zM4yh~#U#a)#Eg!a9`pB@eK8kfqhixzhr~9-E{OdowlR(!ml#(PXNa2_w=V8z+>KTp zTIIK*TRqomO{+t#uC{L1IwmsSoYFpp- zwYHzMJ>M>-U9Wc9cGKFeYxhliR{I|9%iBNNep&lH?Jsxe*r87cONV(Kc62!3F|K1? z$I%^Ucl@~HxlYlYay#ie&F-|N(~qK9QNG9^nk(8Vy4bmW=i<(e&PzJ)>wGglDSmML zbysvB)BV-%2YRr2Wb~-(v7pEPo~)jkJ@q|b z?RhYn3&+Jx$xD-ur3h2xaze#&YwbBLB!?I9Wk?cv?CfTp)J=5v**V4brh|Va@cqU_e#vhsTOl#(v z%yaSt`6&59`7uR|qD(PE@tKmVEKokF{7`v4D>KWUwJz(IUMaoC^m?<`+3cijI(vEc zshs#6P0o^>##~YEsNBW5jlDbf*7RQ5`($31JYC+3yfgXT^GD~um4Bf?TwpC&UvO2G zrFvYoRn1oSQBPCvD~u`}TsXh*`=a=w+M?A(7yD%Nd9=^gVs3H2;unjLm2@c4maHnd z*jL{7@xD9z3Hw#_o8Rwb{~rCV{Wq7gO8b_+RC;_s*8!#h8wa9+B?Dg?_+432+1RoV z2Jr@!4O%ehhjK~zW97RlqANyLyjgLjvY>Ki<+p>o4R#FPJ|uj|h#{+nTpg+&I%{a- zu(V;15Bp+x+u{1*o2vL#L#kF(U4E$Wp_d;zJtAYo)DcG?PI|cE;oXn4eZ=s{M&sbAKm^~=f@^JcH;5;$Co@oJyHF{_9weMIpxXI6Z=ejW0GLfm`Qsl zizm;T{QFZwpV~a7!<30rPCeb{>D5!irdp>Sd#2Yji=O2?tABRibF$~=J$GxGZrbP5 z#nb0ZZzc}?@{<{w#5uwd=N_6wg|c=c7?tA}38 zdu`344vVHQy0KWl_^Ty-mTXv>xOC1k-m-Daepo(a`L5R$udiCscE$7+f2=gEY<#2q zjh(CHt5&_){>_=IS*snZ&%HI`tpk5o|9#V%lr>A%#;u+HHhSCf_K)w3dgti6e(Scs zt9WOyMABhz76~3`!^j>9@u;^`{2iidLP>MrTWWH50@PN z;>ds_2agUu`qi-!#~Q!VeRcM0!`HulGwz$4-%dQvJwENbi0|fn-~Rih|LFdYwT+pL zADvL2*mJVtBn>iliSr8bvV{+|B(_RD3LzrSLz3LFJ6o2mN4AYC^l4%!{zaVf(0Q|OCqdn zvE9T7L~$rKi^Jmbc|lyZPzJyH2TPGh> z@w?8dxOn1Mtt}&N>AI&9)h|`*3b!w_XSO;t_$2+?yHj?2={R+%C~5Zcr{8;d=iz_; z{`&e)j-0+cq-NaIIV(1Ndh~}Y@;*ar>z{dL<;Gpd&RmT|EEbfOL(0VGaWhB}I!mHB zP=c}X(Ol`I7h`Y%Z;t1XrYhP2s ztdj1|1D6NKJ>K#7qGh{!p0>}bxLn@vbmgoH=hwssJA=<4SkZwt!L1RF@{taiQ8g^^ zh+yJd2e2K2jX)OQi2f4}5mKQFnA&2eCOO0dh^W-kQq%*0AjGGl$hs0VG~nC9ycn}0 zR86(>z@w>dE*@}tN&@fN2(^b`rKAMLJ?Z&p^kjtz%Pxm-012ADK?qh0UH5x@kqqI_ zjAe->SrWNO?D|d^s6gz+RCC!Dvpo8v7qgpT%m^2cf+;WDDOd&Yst47vxgJ!acRg5? zTL+cOYSvAZK?FUU*n!-!<-!+ZQqU-)8Nb`R^1>)sdw~Gzyf04*13GUCz=Vj`Eis$2{(pe4OO#ZG{aQtsSpL<1{L@+f}|gm=A3Ya%k{~hDTdeU=X?Y z6Ub=R$7=FPm+O4#l~$9@z1SV1(dkNEpK)~K1bEHAoYpzCw7VRUcrDCYiAxTvQg*A^ z;8Uo`=8CzuP zHNYC5&Rtuf$y}-8)ts3J{n(R_|@1^|*%0cEDOK|y6iV-$h;NINZIj)^R z>;Qb&&%qy1^i+UIF2#Z<$Y@K4-2%iRxMc))&8RWyOUjGNA$1<(^G#|zUhIL;oP+mX zBg!wTaJL*$QDiMK-Er^FEkzs?xX8X={*S8?uox(D_dnkqL$?%eP*h~|*&2krt?r#j zOa^+9)txu4vRiw9mB+h)3)ib0{2Ra^EQK#(gXIKlZ>+Jx&IuVGyz1;4OHue)7zPeI zZxUW6!lP+4o}|Hj072p1eGKCoPb@xO}Z42v7m+^=r`>R0}K6X5@f9e;wf&uh#(`TaAm;T0=FiF9#P3r}d^9{1!{B ziqm6EW8B?_$-`!;@unNJ2E2RhW3QS9s|9e_MlCPA3y$9s@HTIl%QAflQ#`Q@ykSBr z9_Q?38L%w5?%Og#wYlCTqD^?*$JNF9T-L$w9zvuBo796%MC9KP8hA-E0Myb#d@T1M zEtDs9I)B@La_OKQW1AEK>QKpX=O%)i%s-SL|MQ79DhlmUUi#Rl<;h_aP zx97r~Mu$O!s4X5GGYslJsCegLSRi7KabUa(u>JX#DAg}Z*|Y? zVD0*Teixkg^MhgVe?=Q=Afvt0S;ad+pdAQRVW3G2?Y#qlIe3s0H#sl0!vLD|DR zqISayHM#Ko5I<~N*zDR2-`^cLUb^PWc!->AWwHKYd0TAcPzPY=)!HkCK$=U231X{2~oTgP@Nq&5v<}={o$mV#5d6m7{_io(VQCqambK- Y16@Zf7?Q8!JB-NJ(KYBs*Ff|C0Zg4MIsgCw literal 0 HcmV?d00001 diff --git a/src/client/svg/directionsigns.js b/src/client/svg/directionsigns.js new file mode 100644 index 0000000..3be1b1f --- /dev/null +++ b/src/client/svg/directionsigns.js @@ -0,0 +1,21 @@ +const m = require('mithril'); +module.exports = function(width, height) { + + + return [m("svg.detail.convertSvgInline.replaced-svg[data-id='68537'][data-kw='directions7'][height='" + height + "px'][id='imgView'][version='1.1'][viewBox='0 0 418.08 418.079'][width='" + width + "px'][x='0px'][xml:space='preserve'][xmlns='http://www.w3.org/2000/svg'][xmlns:xlink='http://www.w3.org/1999/xlink'][y='0px']", { + style: { + "fill": "grey" + } + }, ["\n", m("g", [ + m("g", [ + m("g", [ + m("path[d='M244.63,117.156h112.744c1.267,0,2.485-0.48,3.411-1.345l23.406-21.85c1.014-0.945,1.589-2.269,1.589-3.655 c0-1.386-0.575-2.709-1.589-3.655l-23.406-21.85c-0.925-0.865-2.146-1.345-3.411-1.345H244.63c-2.762,0-5,2.239-5,5v43.699 C239.63,114.917,241.869,117.156,244.63,117.156z']"), + m("path[d='M360.786,161.338c-0.925-0.865-2.146-1.345-3.411-1.345H244.63c-2.762,0-5,2.239-5,5v43.699c0,2.761,2.238,5,5,5h112.744 c1.267,0,2.485-0.479,3.411-1.345l23.406-21.851c1.014-0.945,1.589-2.269,1.589-3.655c0-1.386-0.575-2.709-1.589-3.655 L360.786,161.338z']"), + m("path[d='M178.448,164.156v-43.699c0-2.761-2.238-5-5-5H60.705c-1.267,0-2.486,0.48-3.412,1.345l-23.406,21.85 c-1.013,0.945-1.588,2.269-1.588,3.655c0,1.386,0.575,2.709,1.588,3.655l23.406,21.85c0.926,0.865,2.146,1.345,3.412,1.345 h112.744C176.21,169.156,178.448,166.917,178.448,164.156z']"), + m("path[d='M242.788,388.078h-17.625V35.162c0-0.494-0.093-0.984-0.271-1.445L212.75,2.537C212.154,1.007,210.68,0,209.039,0 c-1.642,0-3.115,1.007-3.711,2.537l-12.141,31.18c-0.179,0.46-0.271,0.951-0.271,1.445v352.917h-17.625c-8.284,0-15,6.716-15,15 s6.716,15,15,15h67.496c8.285,0,15-6.716,15-15S251.073,388.078,242.788,388.078z']") + ]) + ]), + "\n" + ]), "\n"])] + +} diff --git a/src/client/svg/globe-placeholder.js b/src/client/svg/globe-placeholder.js new file mode 100644 index 0000000..1b9886a --- /dev/null +++ b/src/client/svg/globe-placeholder.js @@ -0,0 +1,13 @@ +const m = require('mithril'); +module.exports = function(width, height) { + return [m("svg.detail.convertSvgInline.replaced-svg[data-id='32266'][data-kw='placeholder3'][height='" + height + "px'][id='imgView'][version='1.1'][viewBox='0 0 514.512 514.513'][width='" + width + "px'][x='0px'][xml:space='preserve'][xmlns='http://www.w3.org/2000/svg'][xmlns:xlink='http://www.w3.org/1999/xlink'][y='0px']", { + style: { + "fill": "grey" + } + }, ["\n", m("g", [ + m("path[d='M352.421,153.246c-1.229-0.302-2.5-0.509-3.817-0.509c-8.867,0-16.084,7.214-16.084,16.083 c0,8.866,7.217,16.081,16.084,16.081c8.865,0,16.083-7.214,16.083-16.081c0-5.352-2.654-10.065-6.686-12.988l42.782-59.161 c1.135,0.08,2.27,0.171,3.416,0.171c26.74,0,48.422-21.681,48.422-48.421C452.622,21.681,430.94,0,404.2,0 s-48.421,21.681-48.421,48.421c0,13.267,5.355,25.286,14.003,34.034L352.421,153.246z M358.634,168.827 c0,5.533-4.504,10.028-10.03,10.028c-5.527,0-10.031-4.495-10.031-10.028s4.504-10.031,10.031-10.031 c0.821,0,1.613,0.127,2.382,0.322l-2.382,9.708l5.857-8.107C356.979,162.549,358.634,165.484,358.634,168.827z M435.586,24.956 c4.451-0.316,8.653,8,9.393,18.557c0.738,10.557-2.271,19.366-6.721,19.677c-4.445,0.316-8.647-7.994-9.387-18.551 C428.133,34.082,431.135,25.269,435.586,24.956z M425.467,446.76c-39.773,38.928-88.029,61.218-143.33,66.49 c-72.056,6.845-135.614-14.139-189.118-63.08c-45.001-41.15-70.35-92.764-77.215-153.277 C1.417,170.109,92.407,50.934,218.265,31.62c12.256-1.883,24.657-2.778,36.993-4.129c0.872,0,1.75,0,2.622,0 c13.21,1.374,26.562,1.959,39.607,4.229c16.32,2.846,31.824,7.016,46.523,12.507c0.131,13.609,4.522,26.569,12.561,37.306 l-8.859,36.112c-0.396,0.029-0.799,0.091-1.2,0.104c-6.904,0.106-11.225-5.122-9.522-11.798c0.881-3.449,2.79-6.632,3.617-10.083 c0.627-2.565,1.425-6.549,0.118-7.838c-5.272-5.175-10.952-10.169-17.183-14.091c-11.225-7.081-22.573-1.9-33.732,0.721 c-1.2,9.114-2.453,10.344-11.142,7.767c-10.341-3.088-20.171-7.403-27.216-16.29c-0.884-1.126-3.002-1.998-4.413-1.844 c-10.672,1.214-21.317,2.612-31.921,4.268c-1.525,0.248-3.916,2.293-3.892,3.472c0.035,2.045,1.386,5.568,2.657,5.792 c3.443,0.606,7.438,0.594,10.648-0.635c4.386-1.702,8.115-5.024,12.383-7.143c5.169-2.565,8.902-0.671,10.374,4.909 c1.75,6.611-0.612,12.214-6,15.651c-7.341,4.669-15.392,8.228-22.993,12.507c-5.337,2.988-10.811,5.943-15.548,9.75 c-3.807,3.062-6.458,7.814-3.431,12.699c2.808,4.54,7.799,3.473,11.939,2.01c4.25-1.501,8.275-3.724,12.232-5.935 c2.415-1.348,4.401-3.449,6.768-4.894c4.72-2.876,7.231-1.9,9.037,3.224c3.026,8.621,8.792,10.619,16.512,5.618 c3.334-2.161,6.336-4.897,9.815-6.774c5.133-2.766,10.636,0.178,11.133,5.568c0.727,7.899,2.565,9.437,10.396,8.559 c4.623-0.521,9.227-1.203,13.838-1.82c0.407,0.473,0.81,0.931,1.217,1.403c-1.607,3.003-2.541,6.821-4.977,8.819 c-3.759,3.062-8.388,5.222-12.915,7.155c-6.579,2.801-12.489,4.489-12.714,4.871c0,0,9.232,3.735,4.362,5.121 c-8.027,2.27-20.177,15.283-2.726,9.883c3.133-0.954,6.325-1.723,10.723-2.917c-3.671,11.042-11.432,15.38-19.112,19.497 c-22.976,12.291-23.785,41.751-12.055,56.87c2.542,3.287,4.667,6.972,6.469,10.72c2.086,4.314,1.941,9.489-2.205,11.76 c-2.784,1.524-8.387,1.205-10.87-0.698c-6.041-4.622-11.511-10.246-16.263-16.243c-6.041-7.604-10.385-16.633-16.778-23.879 c-20.652-23.38-43.958-18.229-63.916-0.63c-5.048,4.454-4.38,8.485,1.188,12.156c1.977,1.289,4.146,2.376,6.348,3.263 c8.86,3.582,17.783,6.995,26.643,10.565c1.823,0.732,3.694,1.587,5.207,2.805c3.068,2.468,3.236,5.106-0.769,6.699 c-2.932,1.156-6.073,1.856-9.17,2.527c-5.816,1.265-11.978,1.625-17.401,3.818c-3.147,1.276-6.756,5.178-7.172,8.286 c-0.358,2.66,3.171,6.289,5.701,8.736c1.889,1.809,5.072,2.199,7.427,3.642c3.275,1.985,6.803,3.925,9.351,6.685 c4.309,4.664,7.356,5.828,12.941,2.701c5.382-2.996,10.562-6.348,15.755-9.67c6.156-3.919,7.317-3.439,10.87,2.861 c4.413,7.844,10.495,14.292,20.375,12.543c7.058-1.266,13.751-4.517,20.62-6.834c4.679-1.584,9.292-3.889,14.098-4.456 c9.835-1.177,17.371,7.146,17.927,18.666c0.55,11.526-4.787,20.155-12.921,27.65c-7.979,7.341-12.271,15.734-8.603,27.143 c3.903,12.129-0.255,22.544-9.531,30.605c-6.434,5.604-13.554,10.468-20.652,15.238c-8.316,5.586-22.16,36.191-19.106,46.973 c0.579,2.021,0.748,2.294,0.597,4.475c-0.792,11.49-6.688,9.469-16.952,11.266c-5.798,1.017-5.231-11.266-6.555-16.881 c-1.277-5.391-1.271-11.384-0.432-16.905c0.825-5.42,3.372-10.58,5.231-15.828c3.88-11,1.07-20.363-7.01-28.349 c-3.534-3.499-7.406-6.667-11.038-10.071c-13.208-12.354-19.618-27.888-20.312-45.679c-0.352-8.961,4.049-13.039,12.927-13.879 c1.859-0.177,3.712-0.425,5.574-0.638c-1.041-7.441-3.771-10.268-11.05-10.729c-6.918-0.42-10.944-4.326-13.607-10.019 c-1.241-2.66-1.466-5.78-2.512-8.547c-2.5-6.603-4.256-13.761-8.136-19.464c-3.497-5.131-6.36-9.559-6.227-16.087 c0.062-3.05-2.131-6.596-4.256-9.129c-4.812-5.707-10.143-10.991-15.415-16.299c-2.069-2.081-4.551-3.756-7.971-6.522 c-0.236,5.222-0.242,8.606-0.57,11.939c-0.47,4.729-0.526,9.661-2.04,14.056c-0.842,2.456-4.442,5.73-6.504,5.533 c-2.627-0.248-6.422-3.227-7.114-5.745c-1.265-4.613-1.605-9.957-0.629-14.647c4.569-22.015,6.508-44.106,3.939-66.496 c-0.937-8.198-2.075-16.37-3.23-25.464c-42.98,50.567-63.57,142.426-21.293,223.616c45.383,87.137,142.515,130.995,237.671,106.843 c24.902-6.324,47.08-16.774,66.385-30.05c-10.403-2.92-26.304-9.315-27.746-49.662c-2.015-56.483,7.063-68.589,12.105-68.589 s8.068-4.043,24.211,14.115s24.21,9.078,25.221-3.026c1.011-12.105,13.116-30.015,18.158-11.473 c3.47,12.761,11.236,27.722,17.39,38.449c11.632-23.501,18.43-48.291,19.961-72.088c-3.074-1.288-6.271-2.417-9.28-3.919 c-13.554-6.797-21.485-17.46-22.07-32.914c-0.438-11.325-2.335-13.653-13.92-16.184c-12.135-2.651-16.007-8.112-12.603-20.058 c2.276-7.964,6.023-15.531,9.434-23.146c3.559-7.947,5.935-15.779,4.108-24.801c-1.638-8.113-1.389-16.385,6.029-23.194 c-6.91-7.864-13.3-15.477-20.108-22.686c-3.21-3.396-5.905-2.16-6.898,2.601c-0.242,1.17-0.201,2.397-0.473,3.561 c-2.175,9.218-7.412,12.25-14.363,8.636l24.86-34.374c7.04-0.47,13.731-2.146,19.955-4.737 c8.027,8.381,15.628,17.442,22.774,27.213c24.334,33.277,39.371,70.622,43.869,111.501 C507.243,321.056,483.221,390.199,425.467,446.76z']"), + "\n" + ]), "\n"])] + + +} diff --git a/src/client/svg/map.js b/src/client/svg/map.js new file mode 100644 index 0000000..d368fdf --- /dev/null +++ b/src/client/svg/map.js @@ -0,0 +1,12 @@ +const m = require('mithril'); +module.exports = function(width, height) { + + return [m("svg.detail.convertSvgInline.replaced-svg[data-id='32364'][data-kw='map32'][height='" + height + "px'][id='imgView'][version='1.1'][viewBox='0 0 484.009 484.009'][width='" + width + "px'][x='0px'][xml:space='preserve'][xmlns='http://www.w3.org/2000/svg'][xmlns:xlink='http://www.w3.org/1999/xlink'][y='0px']", { + style: { + "fill": "grey" + } + }, ["\n", m("g", [ + m("path[d='M457.021,309.299l20.238-159.582L332.072,94.625l-45.974,21.953c-1.419,7.021-3.57,13.854-6.384,20.428l34.803-16.618 l-14.369,154.664l0.804,8.286L194.91,299.333l-8.703,17.165l116.276-17.531l13.405,137.177l15.604-1.537l-13.488-137.969 l1.359-0.213l121.573,15.403l0.295-2.376l18.371,154.282l-126.609-29.223l-164.753,31.387l-1.372-0.26l14.81-140.725l-0.098-0.856 l-0.606-5.272l-20.3-40.075l2.864,25.352l-3.621,0.544L42.475,286.412l0.697-5.781L25.177,138.755l82.171,34.693l-6.859-13.521 c-2.219-2.876-4.229-5.891-6.135-8.958L6.188,113.735L27.373,280.69l-0.399,3.321l-0.295-0.047l-2.409,15.486l0.866,0.118 L7.037,451.605l161.225,30.229l164.438-31.315l145.121,33.49L457.021,309.299z M319.188,280.596l-2.707,0.396l-0.592-5.894 l15.108-162.587l1.785-0.854l127.365,48.326l-17.295,136.264L319.188,280.596z M151.41,462.742L24.329,438.91l16.314-136.918 l119.252,18.478l5.417-0.815l0.606,5.319L151.41,462.742z M183.018,322.799l-2.033-4.008l-0.165-1.478l5.394-0.815L183.018,322.799 z M112.68,146.528l69.248,136.657l68.494-135.194c13.453-15.687,21.634-36.017,21.634-58.268C272.055,40.249,231.802,0,182.326,0 c-49.473,0-89.71,40.249-89.71,89.723c0,21.542,7.637,41.316,20.33,56.805H112.68z M182.332,34.578 c30.402,0,55.147,24.742,55.147,55.145c0,30.401-24.745,55.147-55.147,55.147c-30.402,0-55.145-24.746-55.145-55.147 C127.188,59.32,151.924,34.578,182.332,34.578z']"), + "\n" + ])])] +} diff --git a/src/client/svg/report.js b/src/client/svg/report.js new file mode 100644 index 0000000..03c9cda --- /dev/null +++ b/src/client/svg/report.js @@ -0,0 +1,21 @@ +const m = require('mithril'); +module.exports = function (width, height) { + +return [m("svg.detail.convertSvgInline.replaced-svg[data-id='69087'][data-kw='report1'][height='"+height+"px'][id='imgView'][version='1.1'][viewBox='0 0 422.074 422.073'][width='"+width+"px'][x='0px'][xml:space='preserve'][xmlns='http://www.w3.org/2000/svg'][xmlns:xlink='http://www.w3.org/1999/xlink'][y='0px']", {style: {"enable-background": "new 0 0 422.074 422.073", "fill": "grey"}}, ["\n",m("g", [ + m("g", [ + m("g", [ + m("path[d='M229.001,392.729H44.522V27.274h198.907V82.69c0,5.6,4.534,10.133,10.131,10.133h53.791l0.009,181.564 c9.418,0.215,18.602,1.963,27.266,5.188V77.743c0-2.168-0.863-4.248-2.396-5.787L262.667,2.395 C261.133,0.862,259.053,0,256.881,0H41.796C28.262,0,17.25,11.008,17.25,24.543v370.915c0,13.533,11.012,24.543,24.547,24.543 h206.973C240.466,412.384,233.714,403.114,229.001,392.729z']"), + m("path[d='M404.824,311.648c0-4.586-1.785-8.896-5.027-12.142l-12.844-12.844c-3.244-3.242-7.555-5.027-12.139-5.027 c-4.582,0-8.896,1.785-12.141,5.029l-19.602,19.6c-10.47-7.506-23.304-11.928-37.168-11.928 c-35.273,0-63.867,28.596-63.867,63.869c0,35.271,28.594,63.867,63.867,63.867c35.271,0,63.867-28.597,63.867-63.867 c0-1.43-0.051-2.848-0.145-4.254l30.166-30.166C403.039,320.546,404.824,316.232,404.824,311.648z M385.857,315.467 l-61.43,61.428c-1.295,1.296-3.051,2.021-4.881,2.021h-0.002c-1.832,0-3.588-0.729-4.881-2.023l-28.465-28.51 c-2.691-2.693-2.689-7.062,0.002-9.758l5.483-5.479c2.69-2.693,7.058-2.695,9.755-0.007l18.104,18.058l51.019-51.021 c1.296-1.296,3.052-2.021,4.882-2.021s3.586,0.727,4.881,2.021l5.531,5.53C388.552,308.4,388.552,312.77,385.857,315.467z']"), + m("path[d='M188.141,108.951l-57.438,13.148l13.149-57.438c-20.125-5.047-42.319,0.296-58.059,16.035 c-23.835,23.834-23.835,62.478,0,86.312c23.835,23.835,62.478,23.835,86.313,0C187.843,151.269,193.187,129.075,188.141,108.951z ']"), + m("path[d='M188.689,64.113c-8.097-8.096-17.901-13.439-28.254-16.035l-13.149,57.437l57.438-13.149 C202.128,82.014,196.785,72.209,188.689,64.113z']"), + m("g", [ + m("path[d='M89.161,249.945h20.993c5.813,0,10.542-4.729,10.542-10.543c0-5.814-4.729-10.543-10.542-10.543H89.161 c-5.813,0-10.543,4.729-10.543,10.543C78.618,245.216,83.348,249.945,89.161,249.945z']"), + m("path[d='M170.153,267.859H89.161c-5.813,0-10.543,4.729-10.543,10.543c0,5.813,4.729,10.543,10.543,10.543h80.993 c5.813,0,10.542-4.729,10.542-10.543C180.695,272.588,175.966,267.859,170.153,267.859z']"), + m("path[d='M158.153,306.859H89.161c-5.813,0-10.543,4.729-10.543,10.543c0,5.813,4.729,10.543,10.543,10.543h68.993 c5.813,0,10.542-4.729,10.542-10.543C168.695,311.588,163.966,306.859,158.153,306.859z']") + ]) + ]) + ]), + "\n" + ]),"\n"])] + +} diff --git a/src/client/svg/truck-facing.js b/src/client/svg/truck-facing.js new file mode 100644 index 0000000..5a6c5fe --- /dev/null +++ b/src/client/svg/truck-facing.js @@ -0,0 +1,8 @@ +const m = require('mithril'); +module.exports = function(width, height) { + + return [m("svg.detail.convertSvgInline.replaced-svg[data-id='67828'][data-kw='delivery51'][height='" + height + "px'][id='imgView'][version='1.1'][viewBox='0 0 45.774 45.774'][width='" + width + "px'][x='0px'][xml:space='preserve'][xmlns='http://www.w3.org/2000/svg'][xmlns:xlink='http://www.w3.org/1999/xlink'][y='0px']", { + style: { + } + }, [m("g", [m("path[d='M42.749,27.514c-0.455-1.826-1.817-7.312-1.817-7.312V2.275C40.931,1.018,39.913,0,38.655,0h-15.76h-0.01H7.125 C5.866,0,4.848,1.018,4.848,2.275v17.927c0,0-1.363,5.485-1.818,7.312c-0.003,0.012-0.069,0.178-0.069,0.551v10.486 c0,1.258,1.018,2.275,2.277,2.275h0.11V43.5c0,1.256,1.018,2.274,2.277,2.274h4.172c1.259,0,2.277-1.019,2.277-2.274v-2.674h8.811 h0.008h8.811V43.5c0,1.256,1.019,2.274,2.276,2.274h4.173c1.258,0,2.275-1.019,2.275-2.274v-2.674h0.109 c1.259,0,2.275-1.018,2.275-2.275V28.064C42.817,27.691,42.752,27.525,42.749,27.514z M11.04,36.723 c-1.884,0-3.413-1.527-3.413-3.414c0-1.885,1.527-3.414,3.413-3.414c1.886,0,3.416,1.529,3.416,3.414 C14.456,35.195,12.926,36.723,11.04,36.723z M22.888,25.786H8.155l3.356-13.515h11.377h0.008h11.376l3.356,13.515H22.896H22.888z M34.743,36.723c-1.887,0-3.414-1.527-3.414-3.414c0-1.885,1.527-3.414,3.414-3.414c1.886,0,3.412,1.529,3.412,3.414 C38.155,35.195,36.627,36.723,34.743,36.723z']"), "\n"])])] +} diff --git a/src/client/svg/truck.js b/src/client/svg/truck.js new file mode 100644 index 0000000..fe32828 --- /dev/null +++ b/src/client/svg/truck.js @@ -0,0 +1,9 @@ +const m = require('mithril'); +module.exports = function(width, height, fillColor) { + + return [m("svg.detail.convertSvgInline.replaced-svg[data-id='46007'][data-kw='black331'][height='" + height + "px'][id='imgView'][version='1.1'][viewBox='0 0 612 612'][width='" + width + "px'][x='0px'][xml:space='preserve'][xmlns='http://www.w3.org/2000/svg'][xmlns:xlink='http://www.w3.org/1999/xlink'][y='0px']", { + style: { + fill: fillColor ? fillColor : '' + } + }, [m("g", [m("path[d='M150.424,392.577c-31.865,0-57.697,25.832-57.697,57.697s25.832,57.697,57.697,57.697s57.697-25.832,57.697-57.697 S182.29,392.577,150.424,392.577z M150.424,479.123c-15.933,0-28.848-12.916-28.848-28.848c0-15.933,12.916-28.849,28.848-28.849 c15.932,0,28.848,12.916,28.848,28.849C179.272,466.207,166.357,479.123,150.424,479.123z M452.303,392.577 c-31.865,0-57.696,25.832-57.696,57.697s25.831,57.697,57.696,57.697c31.866,0,57.697-25.832,57.697-57.697 S484.168,392.577,452.303,392.577z M452.303,479.123c-15.933,0-28.848-12.916-28.848-28.848c0-15.933,12.916-28.849,28.848-28.849 c15.933,0,28.849,12.916,28.849,28.849C481.151,466.207,468.236,479.123,452.303,479.123z M602.438,371.778h-9.562v-87.295 c0-10.068-7.806-18.413-17.853-19.083L539.008,263c-11.154-0.744-21.201-7.007-26.778-16.694l-27.115-60.879 c-23.866-57.444-57.487-81.397-90.442-81.397H43.031C19.266,104.029,0,123.294,0,147.06v258.188 c0,23.766,19.266,43.031,43.031,43.031h31.251c1.07-41.109,34.774-74.246,76.141-74.246c41.368,0,75.071,33.137,76.141,74.246 h149.598c1.07-41.109,34.773-74.246,76.141-74.246c41.368,0,75.071,33.137,76.142,74.246h73.993c5.281,0,9.562-4.281,9.562-9.562 v-57.375C612,376.06,607.719,371.778,602.438,371.778z M449.664,257.607H346.04c-5.121,0-9.272-4.151-9.272-9.272v-83.503 c0-5.122,4.151-9.272,9.272-9.272h54.545c6.916,0,13.259,3.849,16.451,9.985l40.854,78.511 C461.102,250.227,456.622,257.607,449.664,257.607z']"), "\n"])])] +} diff --git a/src/client/svg/xcloud.js b/src/client/svg/xcloud.js new file mode 100644 index 0000000..4d5a2e2 --- /dev/null +++ b/src/client/svg/xcloud.js @@ -0,0 +1,57 @@ +const m = require('mithril'); +module.exports = function(width, height, fillColor) { + return [m("svg[height='32'][id='svg2'][inkscape:version='0.91 r13725'][sodipodi:docname='xcloud.svg'][version='1.1'][viewBox='0 0 40 32'][width='40'][x='0px'][xmlns='http://www.w3.org/2000/svg'][xmlns:cc='http://creativecommons.org/ns#'][xmlns:dc='http://purl.org/dc/elements/1.1/'][xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'][xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'][xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'][xmlns:svg='http://www.w3.org/2000/svg'][y='0px']", [ + m("metadata[id='metadata12']", [ + m("rdf:rdf", [ + m("cc:work[rdf:about='']", [ + m("dc:format", "image/svg+xml"), + m("dc:type[rdf:resource='http://purl.org/dc/dcmitype/StillImage']"), + m("dc:title") + ]) + ]) + ]), + m("defs[id='defs10']"), + m("sodipodi:namedview[bordercolor='#666666'][borderopacity='1'][gridtolerance='10'][guidetolerance='10'][id='namedview8'][inkscape:current-layer='g4'][inkscape:cx='19.402957'][inkscape:cy='15.753357'][inkscape:pageopacity='0'][inkscape:pageshadow='2'][inkscape:window-height='745'][inkscape:window-maximized='0'][inkscape:window-width='1881'][inkscape:window-x='138'][inkscape:window-y='427'][inkscape:zoom='3.337544'][objecttolerance='10'][pagecolor='#ffffff'][showgrid='false']"), + m("g[id='g4'][transform='matrix(0.44,0,0,0.44,-2.5613949,-423.68403)']", { + style: { + "fill": "#ff0000" + } + }, [ + m("path[d='m 45.042874,969.00026 c -12.989722,0 -22.060344,11.55001 -21.03125,23.125 -8.363515,0.57321 -14.9687499,7.792 -14.9687499,15.87504 0,9.8523 7.5387799,17 15.9999999,17 l 12,0 c 0.528313,0.01 1.014242,-0.4717 1.014242,-1 0,-0.5284 -0.485929,-1.0075 -1.014242,-1 l -12,0 c -7.3381,0 -14,-6.1607 -14,-15 0,-7.2801 6.291083,-14.00004 14,-14.00004 0.579956,0.007 1.090601,-0.58337 1,-1.15625 -1.50281,-10.70142 6.856644,-21.84375 19,-21.84375 8.157628,0 14.250867,4.75171 17.09375,10.4375 0.23759,0.46603 0.877329,0.67432 1.34375,0.4375 3.686951,-1.84348 8.103936,-1.60639 11.5625,0.46875 3.458564,2.07514 6,5.96181 6,11.65625 0.0089,0.46494 0.384434,0.89614 0.84375,0.96875 6.551424,1.09924 11.156248,7.53519 11.156248,14.03129 0,7.783 -6.268459,14 -15.999998,14 l -10,0 c -0.528313,-0.01 -1.014242,0.4716 -1.014242,1 0,0.5283 0.485929,1.0074 1.014242,1 l 10,0 c 10.606145,0 17.999998,-7.1236 17.999998,-16 0,-7.1804 -4.88297,-14.15421 -12.093748,-15.78129 -0.245947,-5.88289 -3.043944,-10.27637 -6.90625,-12.59375 -3.787467,-2.27248 -8.46508,-2.54887 -12.59375,-0.8125 -3.310103,-5.96808 -9.830947,-10.8125 -18.40625,-10.8125 z m -1.125,45.96874 c -0.757272,0.074 -1.144058,1.1934 -0.59375,1.7188 l 7.28125,7.3125 -7.28125,7.2812 c -0.371761,0.3756 -0.366283,1.0566 0.01147,1.4261 0.18564,0.1816 0.452139,0.2927 0.70728,0.2927 0.266717,0 0.531946,-0.1193 0.71875,-0.3125 l 7.28125,-7.2813 7.28125,7.2813 c 0.190785,0.1927 0.457502,0.312 0.71875,0.3125 0.253696,4e-4 0.517925,-0.124 0.698995,-0.3011 0.37493,-0.3668 0.384322,-1.0406 0.01976,-1.4177 l -7.281255,-7.2812 7.28125,-7.3125 c 0.583613,-0.5623 0.05912,-1.7643 -0.75,-1.7188 -0.257929,0.01 -0.510228,0.1249 -0.6875,0.3125 l -7.28125,7.2813 -7.28125,-7.2813 c -0.211936,-0.2277 -0.534609,-0.3472 -0.84375,-0.3125 z'][id='path6'][inkscape:connector-curvature='0']", { + style: { + "color": "#000000", + "font-style": "normal", + "font-letiant": "normal", + "font-weight": "normal", + "font-stretch": "normal", + "font-size": "medium", + "line-height": "normal", + "font-family": "Sans", + "-inkscape-font-specification": "Sans", + "text-indent": "0", + "text-align": "start", + "text-decoration": "none", + "text-decoration-line": "none", + "letter-spacing": "normal", + "word-spacing": "normal", + "text-transform": "none", + "direction": "ltr", + "block-progression": "tb", + "writing-mode": "lr-tb", + "baseline-shift": "baseline", + "text-anchor": "start", + "display": "inline", + "overflow": "visible", + "visibility": "visible", + "opacity": "1", + "fill": "#ff0000", + "fill-opacity": "1", + "stroke": "none", + "stroke-width": "2", + "marker": "none", + "enable-background": "accumulate" + } + }) + ]), + ])] +} diff --git a/src/client/togoogle.js b/src/client/togoogle.js new file mode 100644 index 0000000..34404f3 --- /dev/null +++ b/src/client/togoogle.js @@ -0,0 +1,8 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +function toGoogle(history) { + if (history && history.la && history.lo) { + return new google.maps.LatLng(history.la, history.lo); + } +} +module.exports = toGoogle; diff --git a/src/client/tomiles.js b/src/client/tomiles.js new file mode 100644 index 0000000..5f2ee16 --- /dev/null +++ b/src/client/tomiles.js @@ -0,0 +1,19 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const KilometersToMiles = require("kilometers-to-miles"); +const ktm = new KilometersToMiles(); +const _ = require('lodash'); +const appState = require('../client/appState'); +const isUserMetric = require('./isUserMetric'); + +module.exports = function (value) { + value = parseFloat(value); + if (!_.isFinite(value)) { + return ''; + } + if (isUserMetric()) { + return parseFloat(value.toFixed(1)); + } else { + return parseFloat(ktm.get(value).toFixed(1)); + } +} diff --git a/src/client/tzoffset.js b/src/client/tzoffset.js new file mode 100644 index 0000000..941435f --- /dev/null +++ b/src/client/tzoffset.js @@ -0,0 +1,31 @@ +/* Copyright (c) 2016 Grant Miner */ + +'use strict'; +function tzOffset() { + return (new Date()).getTimezoneOffset(); +} + +let cache = {}; + +function isDST() { + return (new Date()).getTimezoneOffset() < stdTimezoneOffset(); +} + +function stdTimezoneOffset() { + let fy = (new Date()).getFullYear(); + if (!cache.hasOwnProperty(fy)) { + let maxOffset = new Date(fy, 0, 1).getTimezoneOffset(); + let monthsTestOrder = [6, 7, 5, 8, 4, 9, 3, 10, 2, 11, 1]; + for (let mi = 0; mi < 12; mi++) { + let offset = new Date(fy, monthsTestOrder[mi], 1).getTimezoneOffset(); + if (offset != maxOffset) { + maxOffset = Math.max(maxOffset, offset); + break; + } + } + cache[fy] = maxOffset; + } + return cache[fy]; +} + +module.exports = tzOffset; diff --git a/src/client/user-new.js b/src/client/user-new.js new file mode 100644 index 0000000..20c78a1 --- /dev/null +++ b/src/client/user-new.js @@ -0,0 +1,118 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState';const Device = require('../common/models/Device');const catchhandler = require('./catchhandler'); +const timezones = require('json-loader!timezones.json/timezones.json'); +const User = require('../common/models/User'); +const _ = require('lodash'); +const orgselector = require('./orgselector'); +const formitem = require('./formitem'); +const keyhelper = require('./keyhelper'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + const state = appState.getState(); + ctrl.user = new User(state.usersByID[state.viewID]); + + if (state.usersByID[state.viewID]) { + ctrl.editing = true; + } else { + ctrl.editing = false; + ctrl.user = new User(); + ctrl.user.username = state.viewID; + } + + // appState.getStore().subscribe(function () { + // const state = appState.getState(); + // if (state.usersByID[ctrl.user.username]) { + // ctrl.user = state.usersByID[ctrl.user.username]; + // m.redraw(); + // } + // }) + + ctrl.save = function () { + appState.saveUser(ctrl.user) + .then(function () { + window.history.back(); + }) + .catch(catchhandler); + } +}; + +module.exports.view = function(ctrl, args, extras) { + const state = appState.getState(); + + return m('div', [ + m('.col-md-3'), + m('.col-md-6 business-table', [ + m('.btn', ctrl.editing ? t('Edit User') : t('New User')), + m('form.form-horizontal', [ + Object.keys(ctrl.user).map(function (key) { + + if (!state.user.isAdmin && key === 'isAdmin') { + // only let site admins create site admins + return; + } + + if (key === 'isAdmin' || key === 'isOrgAdmin') { + return m('div.form-group', [m('label.col-md-4 control-label', keyhelper(key) + ':'), m('div.col-md-8', m('input[type=checkbox]', { + onclick: function() { + ctrl.user[key] = this.checked; + }, + checked: ctrl.user[key] + }, timezones.map(function (tz) { + return m('option', { + value: tz.value + }, tz.text); + })))]) + } + + // if (key === 'timezone') { + // return m('div.form-group', [m('label.col-md-2 control-label', key), m('div.col-md-10', m('select.form-control', { + // onchange: m.withAttr('value', ctrl.user[key]), + // value: ctrl.user[key]() + // }, timezones.map(function (tz) { + // return m('option', { + // value: tz.value + // }, tz.text); + // })))]) + // } + + if (key === 'orgid') { + return orgselector(ctrl.user, 4, 8); + // } else if (key === 'type') { + // return m('div.form-group', [m('label.col-md-2 control-label', key), m('div.col-md-10', m('select.form-control', { + // onchange: m.withAttr('value', ctrl.user[key]), + // value: ctrl.user[key]() + // }, Object.keys(ctrl.types).map(function (key) { + // return m('option', { + // value: key + // }, ctrl.types[key]); + // })))]) + } else { + return formitem(ctrl.user, key, 4, 8, key === 'username' && ctrl.editing); + // return m('div.form-group', [m('label.col-md-4 control-label', _.capitalize(key) + ':'), m('div.col-md-8', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.user[key]), + // disabled: ctrl.editing && key === 'username', // id's can't be edited + // value: ctrl.user[key]() + // }))]) + } + }) + ]), + m('.buttons-right', [ + m('button.btn btn-default', { + onclick: function (ev) { + ev.preventDefault(); + window.history.back(); + } + }, t('Cancel')), + ' ', + m('button.btn btn-success', { + onclick: ctrl.save + }, t('Save')) + ]) + ]), + m('.col-md-3') + ]) +}; diff --git a/src/client/user.js b/src/client/user.js new file mode 100644 index 0000000..4a77e26 --- /dev/null +++ b/src/client/user.js @@ -0,0 +1,23 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +let m = require('mithril'); + +module.exports.controller = function(args, extras) { + // this.user = m.prop(); + // this.orgid = m.route.param('orgid'); + // let id = m.route.param('id'); + // if (!id) id = ''; + // + // m.request({ + // url: '/api/organizations/' + this.orgid + '/users/' + id, + // config: identity.withAuth + // }) + // .then(this.user) +}; + +module.exports.view = function(ctrl) { + return m('div.business-table', [ + m('.btn', 'User'), + m('pre', JSON.stringify(ctrl.user(), undefined, 4)) + ]) +}; diff --git a/src/client/users.js b/src/client/users.js new file mode 100644 index 0000000..be8ae4e --- /dev/null +++ b/src/client/users.js @@ -0,0 +1,101 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState'; +const sorts = require('./sorts'); +const catchhandler = require('./catchhandler'); +const _ = require('lodash'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + + ctrl.delete = function (user) { + let result = window.confirm('Are you sure you want to delete ' + user.username + '?'); + + if (result === true) { + appState.deleteUser(user) + .catch(catchhandler); + } + } +}; + +function getSecurtyLevel(user) { + if (user.isAdmin && user.isOrgAdmin) { + return t('Site Admin and Organization Admin'); + } + if (user.isAdmin) + return t('Site Admin'); + if (user.isOrgAdmin) + return t('Organization Admin'); + return t('User'); +} + +module.exports.view = function(ctrl, args, extras) { + const state = appState.getState(); + const subview = state.subview; + const orgid = state.selectedOrg.id; + + let users = _.toArray(state.usersByID); + + if (state.subview != 'ALL') { + users = users.filter(function (user) { + return user.orgid === orgid; + }) + } + + return m('.div', [ + m('.col-md-2'), + m('.col-md-8 business-table', [ + m('button.btn btn-default', { + style: { + 'margin-bottom': '1em' + }, + onclick: function () { + appState.viewNewUser(); + } + }, t('New User')), + m('table.table table-bordered table-striped', sorts(users), [ + m('thead', + m('tr', [ + m('th[data-sort-by=username]', t('Username')), + m('th[data-sort-by=email]', t('Email')), + m('th[data-sort-by=firstname]', t('First Name')), + m('th[data-sort-by=lastname]', t('Last Name')), + m('th[data-sort-by=isOrgAdmin]', t('Security Level')), + ctrl.orgid ? '' : m('th', t('Organization')), + m('th', t('Operations')) + ]) + ), + m('tbody', [ + users.map(function(user) { + return m('tr', [ + m('td', user.username), + m('td', user.email), + m('td', user.firstname), + m('td', user.lastname), + m('td', getSecurtyLevel(user)), + ctrl.orgid ? '' : m('td', appState.getOrgName(user.orgid)), + m('td', [ + m('a.btn btn-primary btn-sm ', { + onclick: function (ev) { + ev.preventDefault(); + appState.viewUserByID(user.username); + } + }, m('span.middle glyphicon glyphicon-pencil'), ' ' + t('Update')), + ' ', + m('a.btn btn-primary btn-sm ', { + onclick: function(ev) { + ev.preventDefault() + ctrl.delete(user); + } + }, m('span.middle glyphicon glyphicon-trash'), ' ' + t('Delete')) + ]) + ]) + }) + ]) + ]) + ]), + m('.col-md-2') + ]) +}; diff --git a/src/client/vehicle-new.js b/src/client/vehicle-new.js new file mode 100644 index 0000000..2bd739c --- /dev/null +++ b/src/client/vehicle-new.js @@ -0,0 +1,110 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const m = require('mithril'); +const catchhandler = require('./catchhandler'); +const Vehicle = require('../common/models/Vehicle'); +const orgselector = require('./orgselector'); +const _ = require('lodash'); +const appState = require('./appState'); +const keyhelper = require('./keyhelper'); + +module.exports.controller = function(args, extras) { + + const ctrl = this; + const state = appState.getState(); + ctrl.vehicle = new Vehicle(state.vehiclesByID[state.viewID]); + + if (state.vehiclesByID[state.viewID]) { + ctrl.editing = true; + } else { + ctrl.editing = false; + ctrl.vehicle = new Vehicle(); + ctrl.vehicle.id = state.viewID; + } + + // appState.getStore().subscribe(function () { + // const state = appState.getState(); + // if (state.vehiclesByID[ctrl.vehicle.id]) { + // ctrl.vehicle = state.vehiclesByID[ctrl.vehicle.id]; + // m.redraw(); + // } + // }) + + ctrl.save = function () { + let p; + if (ctrl.editing) { + p = appState.putVehicle(ctrl.vehicle) + } else { + p = appState.postVehicle(ctrl.vehicle) + } + p.then(function () { + window.history.back(); + }) + .catch(catchhandler); + } +}; +const formitem = require('./formitem'); + +module.exports.view = function(ctrl, args, extras) { + const state = appState.getState(); + + const devices = _.toArray(state.devicesByID).filter(function (device) { + return device.orgid == state.selectedOrg.id; + }) + + return m('.div', [ + m('.col-md-3'), + m('.col-md-6 business-table', [ + m('.btn', ctrl.editing ? 'Edit Vehicle' : 'New Vehicle'), + m('form.form-horizontal', [ + Object.keys(ctrl.vehicle).map(function(key) { + if (key === 'device') { + if (state.user.isAdmin) { + // admins can change devices + return m('div.form-group', [m('label.col-md-4 control-label', keyhelper(key) + ':'), m('div.col-md-8', m('select.form-control', { + onchange: function (ev) { + ctrl.vehicle[key] = ev.target.value; + }, + value: ctrl.vehicle[key] + }, _.union([{id:''}], devices).map(function(device) { + return m('option', { + value: device.imei + }, device.imei); + })))]) + } else { + return m('div.form-group', [ + m('label.col-md-4 control-label', keyhelper(key) + ':'), + m('div.col-md-8', m('select.form-control[disabled]', { + value: ctrl.vehicle[key] + }, m('option', { + value: ctrl.vehicle[key] + }, ctrl.vehicle[key]))) + ]) + } + } else if (key === 'orgid') { + return orgselector(ctrl.vehicle, 4, 8); + } else { + return formitem(ctrl.vehicle, key, 4, 8, key === 'id'); + // return m('div.form-group', [m('label.col-md-4 control-label', _.capitalize(key)), m('div.col-md-8', m('input.form-control', { + // onchange: m.withAttr('value', ctrl.vehicle[key]), + // value: ctrl.vehicle[key]() + // }))]) + } + }) + ]), + m('.buttons-right', [ + m('button.btn btn-default', { + onclick: function(e) { + window.history.back() + } + }, 'Cancel'), + ' ', + m('button.btn btn-success', { + onclick: ctrl.save + }, 'Save') + ]) + + ]), + m('.col-md-3') + ]) +}; diff --git a/src/client/vehicle.js b/src/client/vehicle.js new file mode 100644 index 0000000..75b9999 --- /dev/null +++ b/src/client/vehicle.js @@ -0,0 +1,505 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {translate as t} from './i18n'; +import m from 'mithril'; +import appState from './appState'; + +const catchhandler = require('./catchhandler'); +const navbar = require('./navbar'); +const users = require('./users'); +const Status = require('../common/status'); +const helpers = require('../common/helpers'); +const tzOffset = require('./tzoffset'); +const tomiles = require('./tomiles'); +const hidenan = require('../common/hidenan'); +const toGoogle = require('./togoogle'); +const moment = require('moment'); +const pikaday = require('pikaday2').default; +const tohhmmss = require('../common/tohhmmss'); +const street = require('../common/addressdisplay').street; +const city = require('../common/addressdisplay').city; +const renderState = require('../common/addressdisplay').state; +const milesfield = require('../common/milesfield'); +const _ = require('lodash'); +const animation = require('./markers/vehicleanimation'); +const ClickListenerFactory = require('./markers/clicklistenerfactory'); +const j2c = require('j2c'); +const todir = require('../common/todir'); +const isUserMetric = require('./isUserMetric'); +const formatDate = require('./formatDate'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + const state = appState.getState(); + + ctrl.rollup = m.prop(true); + ctrl.highlightIgnition = m.prop(false); + ctrl.highlightStarts = m.prop(false); + ctrl.reverseOrder = m.prop(false); + ctrl.rawData = m.prop(false); + ctrl.vehiclehistory = m.prop([]); + ctrl.adjustedVehicleHistory = m.prop([]); + ctrl.speed = 0; + ctrl.selecteditem = m.prop({}); + ctrl.startDate = m.prop(); + ctrl.endDate = m.prop(); + ctrl.firstRowClicked = false; + + if (state.startDate) { + ctrl.startDate(new Date(state.startDate)); + } + + if (state.endDate) { + ctrl.endDate(new Date(state.endDate)); + } + + ctrl.selectDays = function () { + const state = appState.getState(); + // if (ctrl.startDate() != state.startDate) { + appState.selectDays(ctrl.startDate(), moment(ctrl.endDate()).add(1, 'day').toDate()); + // } + } + + ctrl.updated = m.prop(); + ctrl.calculateDistanceBetween = m.prop('start'); + + animation.controller(this); + ctrl.progressElem = animation.progress; + + ctrl.clickItem = function(item) { + if (ctrl.selecteditem() === item) { + ctrl.selecteditem({}); + ClickListenerFactory.closeInfoWindow(); + } else { + ctrl.selecteditem(item); + animation.clickMarkerByID(item.id); + } + } + + ctrl.play = animation.play; + ctrl.pause = animation.pause; + ctrl.stop = animation.stop; + ctrl.isPausable = animation.isPausable; + ctrl.isPlayable = animation.isPlayable; + ctrl.isStoppable = animation.isStoppable; + + ctrl.speedChange = function (ev) { + const val = parseInt(ev.target.value, 10); + switch (val) { + case 0: animation.setSpeed(400); + break; + case 1: animation.setSpeed(250); + break; + case 2: animation.setSpeed(100); + break; + case 3: animation.setSpeed(50); + break; + case 4: animation.setSpeed(35); + break; + case 5: animation.setSpeed(20); + break; + case 6: animation.setSpeed(15); + break; + case 7: animation.setSpeed(10); + break; + case 8: animation.setSpeed(5); + break; + case 9: animation.setSpeed(1); + break; + default: animation.setSpeed(0); + break; + } + } + animation.setSpeed(1); + + ctrl.recalculateAdjustedVehicleHistory = function recalculateAdjustedVehicleHistory() { + const state = appState.getState(); + const vehicle = state.selectedVehicle; + const hist = state.selectedVehicleHistory; + ctrl.vehiclehistory(hist); + let res = _.cloneDeep(state.selectedVehicleHistory); + + if (ctrl.rawData()) { + if (ctrl.rollup()) { + res = helpers.rollup(res); + } + if (!ctrl.reverseOrder()) { + res.reverse(); + } + } else { + if (!state.verbose) { + res = res.filter(helpers.isNotVerbose); + } + + res = helpers.cleanData(res); + res = helpers.mileageChange(res); + + if (ctrl.rollup()) { + res = helpers.rollup(res); + } + res = helpers.addStartStop(res); + + if (ctrl.calculateDistanceBetween() === 'start') { + res = helpers.startStopMileage(res); + } else { + res = helpers.ignitionMileage(res); + } + + if (!ctrl.reverseOrder()) { + res.reverse(); + } + } + + ctrl.adjustedVehicleHistory(res); + } + + ctrl.recalculateAdjustedVehicleHistory(); + + ctrl.previouslySelectedVehicle = null; + + appState.getStore().subscribe(function () { + const state = appState.getState(); + if (state.selectedVehicle != ctrl.previouslySelectedVehicle) { + ctrl.firstRowClicked = false; + ctrl.previouslySelectedVehicle = state.selectedVehicle; + } + + ctrl.startDate(new Date(state.startDate)); + ctrl.endDate(new Date(state.endDate)); + + // ctrl.startDatePicker.setDate(state.startDate); + // ctrl.endDatePicker.setDate(state.endDate); + + ctrl.recalculateAdjustedVehicleHistory(); + m.redraw(); + }); + + const root = require('./root'); + ctrl.animationConfig = function (el, isInitialized) { + // relocate the animation controls when the map gets big/small + const mapEl = root.getMapElement(); + if (mapEl) { + const cur = el.getBoundingClientRect(); + const r = mapEl.getBoundingClientRect(); + el.style.position = 'absolute'; + el.style.top = r.height - cur.height - 30 + 'px'; + } + } +}; + + +module.exports.view = function(ctrl, args, extras) { + const state = appState.getState(); + const advancedUI = state.user.advancedMode; + + return m('div', [ + m('.business-table', [ + m('div', + advancedUI ? null : [ + m('span', t('Select Day') + ' '), + m('span.padrt', { + config: function(el, isInitialized) { + if (isInitialized) + return; + const input = document.createElement('input'); + el.appendChild(input); + + ctrl.startDatePicker = new pikaday({ + defaultDate: ctrl.startDate(), + setDefaultDate: true, + field: input, + onSelect: function() { + ctrl.startDate(this.getDate()); + ctrl.endDate(this.getDate()); + ctrl.selectDays(); + } + }); + }, + }) + ], + m('button.btn btn-xs btn-primary btn-pad', { + onclick: function () { + ctrl.firstRowClicked = false; + appState.update(); + } + }, t('Refresh')), + ' ', + // m('span', 'Updated: '), + // m('span.padrt.updated-border', (!state.lastUpdated ? '' : moment(state.lastUpdated).format('h:mm:ss A'))), + // ' ', + m('a', { + href: '/api/organizations/' + + state.selectedOrg.id + '/vehiclehistory/' + + state.selectedVehicle.id + '?format=excel' + + '&latlong=' + state.showLatLong + + '&rollupStationaryEvents=' + ctrl.rollup() + + '&verbose=' + (state.verbose ? 'true' : 'false') + + '&startDate=' + encodeURIComponent(ctrl.startDate().toISOString()) + + '&endDate=' + encodeURIComponent(moment(ctrl.endDate()).add(1, 'day').toISOString()) + + '&calculateDistanceBetween=' + ctrl.calculateDistanceBetween() + + '&reverse=' + (ctrl.reverseOrder() ? 'true' : 'false') + + '&tzOffset=' + encodeURIComponent(tzOffset()), + style: { + cursor: 'pointer', + 'margin-left': '1em' + } + }, m('img', { + src: 'images/excel-icon.png', + }), ' ' + t('Excel')), + + m('div', { + config: ctrl.animationConfig, + style: { + 'background-color': 'rgb(221, 221, 221)' + } + }, [ + m('button.btn btn-xs btn-success glyphicon glyphicon-play', { + onclick: ctrl.play, + disabled: !ctrl.isPlayable() + }), + ' ', + m('button.btn btn-xs btn-warning glyphicon glyphicon-pause', { + onclick: ctrl.pause, + disabled: !ctrl.isPausable() + }), + ' ', + m('button.btn btn-xs btn-danger glyphicon glyphicon-stop', { + onclick: ctrl.stop, + disabled: !ctrl.isStoppable() + }), + m('progress', { + value: 0, + style: { + 'margin-left': '1em' + }, + config: ctrl.progressElem + }), + m('input[type=range]', { + min: 0, + max: 10, + onchange: ctrl.speedChange, + config: function (el, isInitialized) { + if (!isInitialized) { + el.value = 9; + } + } + }), + ]), + !advancedUI ? null : [ + m('label', t('Showing:')), + m('div', { + config: function(el, isInitialized) { + if (isInitialized) + return; + const input = document.createElement('input'); + el.appendChild(input); + + ctrl.startDatePicker = new pikaday({ + defaultDate: ctrl.startDate(), + setDefaultDate: true, + field: input, + onSelect: function() { + ctrl.startDate(this.getDate()); + ctrl.selectDays(); + } + }); + }, + }), + m('label', t('Through the end of:')), + m('div', { + config: function(el, isInitialized) { + if (isInitialized) + return; + const input = document.createElement('input'); + el.appendChild(input); + + ctrl.endDatePicker = new pikaday({ + defaultDate: ctrl.endDate(), + setDefaultDate: true, + field: input, + onSelect: function() { + ctrl.endDate(this.getDate()); + ctrl.selectDays(); + } + }); + }, + }), + ], + !advancedUI ? null : m('form.nowrap', { + style: { + display: 'inline', + } + }, [ + m('br'), + m('label', t('Calculate distances between: ')), + m('label', { + style: { + 'margin-left': '0.5em' + } + }, m('input[type=radio][name=speed]', { + checked: ctrl.calculateDistanceBetween() === 'ignition', + onchange: function (a) { + ctrl.calculateDistanceBetween('ignition'); + ctrl.recalculateAdjustedVehicleHistory() + }, + value: 'ignition' + }), t('Ignition')), + + m('label', { + style: { + 'margin-left': '0.5em' + } + }, m('input[type=radio][name=speed]', { + checked: ctrl.calculateDistanceBetween() === 'start', + onchange: function (ev) { + ctrl.calculateDistanceBetween('start'); + ctrl.recalculateAdjustedVehicleHistory() + }, + value: 'start' + }), t('Start/Stop')) + + ]), + m('br'), + m('.nowrap', [ + m('label.padrt', m('input[type=checkbox]', { + onclick: function() { + ctrl.highlightStarts(this.checked); + }, + checked: ctrl.highlightStarts() + }), t('Highlight starts')), + + !advancedUI ? null : m('label.padrt', m('input[type=checkbox]', { + onclick: function() { + ctrl.highlightIgnition(this.checked); + }, + checked: ctrl.highlightIgnition() + }), t('Highlight ignition')), + + m('label.padrt', m('input[type=checkbox]', { + onclick: function() { + ctrl.reverseOrder(this.checked); + ctrl.recalculateAdjustedVehicleHistory(); + }, + checked: ctrl.reverseOrder() + }), t('Reverse Order')), + + m('label.padrt', m('input[type=checkbox]', { + onclick: function() { + appState.setShowVerbose(this.checked); + ctrl.recalculateAdjustedVehicleHistory(); + }, + checked: state.verbose + }), t('Verbose')), + + m('label.padrt', m('input[type=checkbox]', { + onclick: function() { + appState.setShowLatLong(this.checked); + }, + checked: state.showLatLong + }), t('LAT/LONG')), + + state.user.isAdmin || advancedUI ? m('label.padrt', m('input[type=checkbox]', { + onclick: function() { + ctrl.rollup(this.checked); + ctrl.recalculateAdjustedVehicleHistory(); + }, + checked: ctrl.rollup() + }), t('Rollup idling & parked')) : null, + + (state.user.isAdmin) ? [m('label', m('input[type=checkbox]', { + onclick: function() { + ctrl.rawData(this.checked); + ctrl.recalculateAdjustedVehicleHistory(); + }, + checked: ctrl.rawData() + }), t('Raw')), m('br') ]: null, + + ]), + + !advancedUI ? null : m('label', 'Showing ' + ctrl.adjustedVehicleHistory().length + (ctrl.vehiclehistory().length === 1 ? ' event' : ' events') + (ctrl.vehiclehistory().length === 0 ? ' (Try a different date range?)' : '')), + m('table.table table-bordered table-striped', { + style: { + cursor: 'pointer', + } + }, [ + m('thead', [ + m('td', t('Date')), + m('td', t('Address')), + m('td', t('City')), + m('td', t('State')), + m('td', isUserMetric() ? t('Kilometers') : t('Miles')), + state.verbose ? m('td', t('Odometer')) : '', + state.verbose ? m('td', t('Engine Hours')) : '', + m('td', t('Dir')), + m('td', isUserMetric() ? t('km/h') : t('mph')), + state.showLatLong ? m('td', t('Lat')) : '', + state.showLatLong ? m('td', t('Long')) : '', + m('td', t('Status')), + state.verbose ? m('td', t('Online')) : '', + state.verbose ? m('td', t('Battery %')): '', + m('td', t('GPS')), + ctrl.rawData() ? m('td', t('Raw')): null, + ]), + m('tbody', + ctrl.adjustedVehicleHistory().length < 1 ? m('div', t('No vehicle history for this day')) : + ctrl.adjustedVehicleHistory().map(function(item, index) { + return m('tr', { + config: function (el, isInitialized) { + if (!ctrl.firstRowClicked && item.la != null && item.lo != null) { + ctrl.firstRowClicked = true; + setTimeout(() => { + el.click(); + ctrl.firstRowClicked = true; + }, 0); + } + }, + class: ctrl.highlightIgnition() && (item.cmd === 'IGN') || ctrl.highlightStarts() && item.statusOverride === 'Start' ? 'highlight-igniton' : '', + onclick: function(ev) { + ctrl.clickItem(item); + }, + key: item.id, + style: j2c.inline({ + 'background-color': item.id === ctrl.selecteditem().id ? '#FEE0C6' : '' + }) + }, [ + m('td', formatDate(item.d)), + m('td', street(item)), + m('td', city(item)), + m('td', renderState(item)), + m('td', { + style: j2c.inline({ + color: item.idleTime != null ? Status.getStatusColor(item) : '' + }) + }, milesfield(item, isUserMetric())), + state.verbose ? m('td', hidenan(tomiles(item.m))) : '', // total mileage + state.verbose ? m('td', item.h) : '', + m('td', todir(item)), + m('td', hidenan(tomiles(item.s))), + state.showLatLong ? m('td', item.la) : '', + state.showLatLong ? m('td', item.lo) : '', + ctrl.rawData() ? m('td', { + style: j2c.inline({ + color: Status.getStatusColor(item) + }) + }, item.cmd + ' ' + Status.getStatus(item)) : + m('td', { + style: j2c.inline({ + color: Status.getStatusColor(item) + }) + }, t(Status.getStatus(item))), + state.verbose ? m('td', item.b ? t('Buffered') : t('Yes')) : '', + state.verbose ? m('td', item.bp) : '', + m('td', helpers.getAccuracyAsImg(item.g)), + ctrl.rawData() ? m('td', m('pre', { + // if you click the raw message, reformat it nicely + onclick: function (el) { + el.target.innerText = JSON.stringify(item, null, 4); + } + }, JSON.stringify(item))) : null, + ]) + })) + ]) + ) + ]) + ]) +}; diff --git a/src/client/vehicles.js b/src/client/vehicles.js new file mode 100644 index 0000000..9c04221 --- /dev/null +++ b/src/client/vehicles.js @@ -0,0 +1,80 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const m = require('mithril'); +const sorts = require('./sorts'); +const catchhandler = require('./catchhandler'); +const appState = require('./appState'); + +module.exports.controller = function(args, extras) { + const ctrl = this; + + ctrl.delete = function (vehicle) { + let result = window.confirm('Are you sure you want to delete vehicle ' + vehicle.name + '?'); + + if (result === true) { + appState.deleteVehicle(vehicle) + .catch(catchhandler); + } + } +}; + +module.exports.view = function(ctrl, args, extras) { + const state = appState.getState(); + + return m('div', [ + m('.col-sm-1'), + m('.business-table.col-sm-10', [ + m('button.btn btn-default', { + style: { + 'margin-bottom': '1em' + }, + onclick: function (ev) { + ev.preventDefault(); + appState.viewNewVehicle(); + } + }, 'New Vehicle'), + m('table.table table-bordered table-striped', sorts(state.vehiclesByID), [ + m('thead', + m('tr', [ + m('th[data-sort-by=name]', 'Name'), + m('th[data-sort-by=device]', 'Device IMEI'), + m('th[data-sort-by=plate]', 'Plate'), + m('th[data-sort-by=vin]', 'VIN'), + m('th', '') + ]) + ), + m('tbody', [ + _.toArray(state.vehiclesByID).map(function(vehicle) { + return m('tr', [ + m('td', vehicle.name), + m('td', m('a', { + onclick: function (ev) { + ev.preventDefault(); + appState.viewDeviceByID(vehicle.device); + }, + }, vehicle.device)), + m('td', vehicle.plate), + m('td', vehicle.vin), + m('td', [ + m('a.btn btn-sm btn-primary btn-warning', { + onclick: function (ev) { + ev.preventDefault(); + appState.viewVehicleByID(vehicle.id); + }, + }, m('span.middle glyphicon glyphicon-pencil'), ' Update'), + ' ', + m('a.btn btn-primary btn-sm btn-danger', { + onclick: function (ev) { + ev.preventDefault(); + ctrl.delete(vehicle); + }, + }, m('span.middle glyphicon glyphicon-trash'), ' Delete') + ]) + ]) + }) + ]) + ]) + ]), + m('.col-sm-1') + ]) +}; diff --git a/src/client/withAuth.js b/src/client/withAuth.js new file mode 100644 index 0000000..a330348 --- /dev/null +++ b/src/client/withAuth.js @@ -0,0 +1,12 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const Cookies = require('cookies-js'); + +module.exports = function withAuth (xhr) { + const jwt = Cookies.get('jwt'); + + if (jwt) { + xhr.setRequestHeader('Authorization', 'Bearer ' + jwt); + } + return xhr; +} diff --git a/src/common/addressdisplay.js b/src/common/addressdisplay.js new file mode 100644 index 0000000..31eb44e --- /dev/null +++ b/src/common/addressdisplay.js @@ -0,0 +1,48 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {get} from 'lodash'; + +export function full(item) { + if (item.ad) { + return item.ad.formattedAddress; + } +} +export function street(item) { + if (item.ad) { + let ad = item.ad; + + if (ad.streetNumber || ad.streetName) { // Google + let toRet = []; + if (ad.streetNumber) + toRet.push(ad.streetNumber); + if (ad.streetName) + toRet.push(ad.streetName); + return toRet.join(' '); + } + // else if (ad.name) { // local-reverse-geocoder + // return ad.name; + // } + } +} +export function city(item) { + if (item.ad) { + if (item.ad.city) { // Google + return get(item, 'ad.city'); + } else if (item.ad.name) { // local-reverse-geocoder + return get(item, 'ad.name'); + } + + } +} +export function state(item) { + if (item.ad) { + if (get(item, 'ad.administrativeLevels.level1long')) { + return get(item, 'ad.administrativeLevels.level1long'); + } else if (item.ad.admin1Code) { + return get(item, 'ad.admin1Code.name'); + } + // else if (item.ad.admin2Code) { + // return get(item, 'ad.admin2Code.name'); + // } + } +} diff --git a/src/common/db.js b/src/common/db.js new file mode 100644 index 0000000..b2b1b78 --- /dev/null +++ b/src/common/db.js @@ -0,0 +1,12 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const options = require('../../config/database.js'); +const r = module.exports = require('rethinkdbdash')(options); +require('rethink-handle-uncaught')(r, { + filter: function (errorOrException) { + if (errorOrException.msg === 'Malicious Path') { + return false; + } + return true; + } +}); diff --git a/src/common/helpers.js b/src/common/helpers.js new file mode 100644 index 0000000..581b809 --- /dev/null +++ b/src/common/helpers.js @@ -0,0 +1,481 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import _ from 'lodash'; +import moment from 'moment'; +import {getStatus, isIdle, isPark, isStop, isTow} from './status'; + +export function getAccuracy(i) { + // https://en.wikipedia.org/wiki/Dilution_of_precision_(GPS) + if (!_.isNumber(i)) { + return null; + } + i = Number(i); + if (i === 0) { + return 'None' + } else if (i <= 1 && i > 0 ) { + return 'Ideal'; + } else if (i <= 2) { + return 'Excellent'; + } else if (i <= 5) { + return 'Good'; + } else if (i <= 10) { + return 'Moderate'; + } else if (i <= 20) { + return 'Fair'; + } else { + return 'Poor'; + } +} + +export function getAccuracyAsStars (i) { + i = Number(i); + if (i === 0) { + return '' + } else if (i <= 1 && i > 0 ) { + return '☆☆☆☆☆'; + } else if (i <= 2) { + return '☆☆☆☆'; + } else if (i <= 5) { + return '☆☆☆'; + } else if (i <= 10) { + return '☆☆'; + } else return '☆'; +} + +export function getAccuracyAsImg (i) { + if (!_.isNumber(i)) { + return null; + } + i = Number(i); + if (i === 0) { + return m('img', { + src: 'images/signal0.png' + }) + } else if (i <= 1 && i > 0 ) { + return m('img', { + src: 'images/signal5.png' + }) + } else if (i <= 2) { + return m('img', { + src: 'images/signal4.png' + }) + } else if (i <= 5) { + return m('img', { + src: 'images/signal3.png' + }) + } else if (i <= 10) { + return m('img', { + src: 'images/signal2.png' + }) + } else if (i <= 20) { + return m('img', { + src: 'images/signal1.png' + }) + } else { + return m('img', { + src: 'images/signal0.png' + }) + } +} + +export function toGoogle(history) { + return { + lat: history.l.coordinates[1], + lng: history.l.coordinates[0] + } +} + +export function cleanItem(item) { + if (item.cmd === 'TOW') { + item.ig = false; + item.mo = true; + } + + // Low Speed Moving Override + // e.g., if speed is less than 1km/h, override moving to be false. + // let lowspeed = 3.5; + // if (item.s < lowspeed) { + // item.mo = false; + // item.faketow = false; + // if (item.cmd === 'TOW') { + // item.cmd = 'FRI'; + // item.ig = false; + // } + // } + return item; +} + +export function cleanData(history) { + if (!history) { + return []; + } + + return history.map(function (item) { + if (item.last) { + item.last = cleanItem(item.last); + return item; + } else { + return cleanItem(item); + } + }) +} + +/** +Non verbose status, e.g. we want to display it on the org view. +*/ +export function isNotVerbose(item) { + // return ['BPL', 'BTC', 'CRA', 'EMG', 'EPS', 'FLA', + // 'FRI', 'GIN', 'GOT', 'GSS', 'HBM', 'IDN', 'IDL', 'IGF', 'IGN', + // 'JDC', 'JDS', 'LSP', 'MPF', 'MPN', 'PFA', 'PNA', 'SOS', 'SPD', + // 'STC', 'TMP', 'TOW', 'OPN', 'OPF', 'OWH', 'RTO' + // ].indexOf(item.cmd) > -1; + + if (item.cmd === 'FRI') { + const status = getStatus(item); + return ! (['Sensor Motion', 'Sensor Rest', 'Fake Towing', 'Towing (FRI)' + ].indexOf(status) > -1); + + } else return [ + // , 'BPL' + // , 'BTC' + , 'CRA' + , 'EMG' + // , 'EPS' + , 'FLA' + // , 'FRI' + , 'GIN' + , 'GOT' + // , 'GSS' + , 'HBM' + , 'IDN' + , 'IDL' + , 'IGF' + , 'IGN' + , 'JDC' + , 'JDS' + , 'LSP' + // , 'MPF' + // , 'MPN' + , 'PFA' + , 'PNA' + , 'SOS' + , 'SPD' + // , 'STC' + , 'TMP' + , 'TOW' + // , 'OPN' + // , 'OPF' + , 'OWH' + // , 'RTO' + ].indexOf(item.cmd) > -1; +} + +export function onlyVisibleHistory(history) { + if (!history) { + return []; + } else { + return history.filter(isNotVerbose); + } +} + +export function containsMotionInformation(item) { + if (['FRI', 'TOW', 'SPD', 'MPF', 'MPN', 'PFA', 'PNA', 'IGN', 'IGF', 'HBM', 'RTL'].indexOf(item.cmd) > -1) { + return true; + } else { + return false; + } +} + +// is item a motion event +// towing is not considered +export function isMotion(item) { + if (!containsMotionInformation(item)) { + throw new Error("Item does not contain motion information"); + } + if (!isNotVerbose(item)) { + return false; + } + let status = getStatus(item); + if (isTow(item)) { + return false; + } + + if (item.cmd === 'PFA' + || item.cmd === 'PNA' + || item.cmd === 'IGF' + || item.cmd === 'IGN' + || item.cmd === 'MPF' + || item.cmd === 'MPN') { + return false; + } + + if (item.cmd === 'FRI' || item.cmd === 'TOW' || item.cmd === 'SPD') { + if (isIdle(item)) + return false; + if (isStop(item)) + return false; + if (isPark(item)) + return false; + } + return true; + // + // let ismotion = item != null + // && (item.cmd === 'FRI' || item.cmd === 'TOW' || item.cmd === 'SPD' || item.cmd === 'HBM' || item.cmd === 'OBD' || item.cmd === 'BPL') + // && !isPark(item) && !isIdle(item) && !isTow(item) + // return ismotion; +} + +export function mileageChange(history) { + // compute mileage between events and mileage for every event, since some don't report it. + let i; + if (!history) { + return [] + } else return history.reduce(function (output, current, index, array) { + if (!_.isFinite(array[index].m)) { + for (i = index; i >= 0; i--) { + if (_.isFinite(array[i].m)) { + current.m = array[i].m; + break; + } + } + } + if (!_.isFinite(array[index].tm)) { + for (i = index; i >= 0; i--) { + if (_.isFinite(array[i].tm)) { + current.tm = array[i].tm; + break; + } + } + } + + if (index === 0) { // first item + current.mc = 0; // mileage change; mileage between single events. + } else { + let last = output[output.length - 1]; + if (last != null) { + if (!_.isFinite(current.m)) { + current.m = last.m; + } + current.mc = current.m - last.m; + } + + // Compute idle/parked times + if (isIdle(current)) { + if (last) { + current.idleTime = moment(current.d).diff(last.d); + } else { + current.idleTime = 0; + } + } + + if (isPark(current)) { + if (last) { + current.idleTime = moment(current.d).diff(last.d); + } else { + current.idleTime = 0; + } + } + } + + + + output.push(current); + return output; + }, []) +} + +export function ignitionMileage(history) { + // mileage between ignitions + if (!history) { + return [] + } else return history.reduce(function (output, current, index, array) { + if (index === 0 || current.cmd === 'IGF' || current.cmd === 'IGN') { // first item and ignition changes reset the mileages. + current.tm = 0; // trip mileage; mileage between ignition events. + } else { + let last = output[output.length - 1]; + if (last != null) { + current.tm = last.tm + current.mc; + } + } + + output.push(current); + return output; + }, []) +} + +export function startStopMileage(history) { + // mileage between starts/stops + if (!history) { + return [] + } else return history.reduce(function (output, current, index, array) { + if (index === 0) { + current.tm = 0; // trip mileage; mileage between start/stop events. + } + + if (current.statusOverride === 'Start') { + current.tm = 0; + } else { + let last = array[index - 1]; + if (last != null) { + current.tm = current.mc + last.tm; + } else { + current.tm = current.mc; + } + } + output.push(current); + return output; + }, []); +} + +export function addStartStop(history) { + // this operates on an array in time-ascending order + let started = false; + + if (!history) { + return [] + } else return history.reduce(function (output, current, index, array) { + + if (started) { // if we were moving + if (containsMotionInformation(current)) { + if (!isMotion(current)) { // and now we are stopped + started = false; + let fake = _.clone(current); + fake.statusOverride = 'Stopped'; + fake.id = fake.id + 'fakestop'; + fake.mc = 0; + fake.s = 0; + fake.tm = output.tm; + output.push(fake); + } else { + + } + } else { + + } + } + + if (!started) { // if we were stopped + if (containsMotionInformation(current)) { + if (isMotion(current)) { // and now we're moving + started = true; + if (current.mc > 0) { // if this motion event has a mileage change + // add a fake start event + let fake = _.clone(current); + fake.statusOverride = 'Start'; + fake.id = fake.id + 'fakestart'; + fake.mc = 0; + fake.s = 0; + // if (earlier) { + // fake.m = earlier.m; + // } + output.push(fake); + } else { + // otherwise this starts at a 0 mileage change, we can just make it a start itself, so we don't add a start then a motion with both '0' mileage change. + current.statusOverride = 'Start'; + } + } else { + + } + } else { + + } + } + output.push(current); + + // let earlier = array[index - 1]; + // let later = array[index + 1]; + // let fake; + // let pushedCurrentValue = false; + // + // if (containsMotionInformation(current) && isMotion(current) && containsMotionInformation(earlier) && !isMotion(earlier)) { + // + // if (current.mc > 0) { // if this motion event has a mileage change + // // add a fake start event + // fake = _.clone(current); + // fake.statusOverride = 'Start'; + // fake.id = fake.id + 'fakestart'; + // fake.mc = 0; + // fake.s = 0; + // if (earlier) { + // fake.m = earlier.m; + // } + // output.push(fake); + // } else { + // // otherwise this starts at a 0 mileage change, we can just make it a start itself, so we don't add a start then a motion with both '0' mileage change. + // current.statusOverride = 'Start'; + // } + // } + // + // output.push(current); + // + // if (index != array.length - 1 && containsMotionInformation(current) && isMotion(current) && containsMotionInformation(later) && !isMotion(later)) { // add a fake stopped event + // fake = _.clone(current); + // fake.statusOverride = 'Stopped'; + // fake.id = fake.id + 'fakestop'; + // fake.mc = 0; + // fake.s = 0; + // fake.tm = output.tm; + // output.push(fake); + // } + return output; + }, []); +} + +export function rollup(history) { + + let idleStart, parkedStart; + + // this operates on an array in time-ascending order + if (!history) { + return [] + } else return history.reduce(function (output, current, index, array) { + let later = array[index + 1]; + let earlier = array[index - 1]; + + if (containsMotionInformation(current) && isIdle(current)) { + if (idleStart == null) { + if (earlier != null) { + idleStart = earlier.d; + } else { + idleStart = current.d; + } + } + + if (later == null || (containsMotionInformation(later) && !isIdle(later))) { + current.idleTime = moment(current.d).diff(idleStart); + idleStart = null; + return output.concat(current); + } else { + return output; + } + } + + if (containsMotionInformation(current) && isPark(current)) { + if (parkedStart == null) { + if (earlier != null) { + parkedStart = earlier.d; + } else { + parkedStart = current.d; + } + } + + if (later == null || (containsMotionInformation(later) && !isPark(later))) { + current.idleTime = moment(current.d).diff(parkedStart); + parkedStart = null; + return output.concat(current); + } else { + return output; + } + } + + return output.concat(current); + }, []) +} + +export function nullToBlank (x) { + if (x == null || _.isNaN(x)) { + return ''; + } else { + return x; + } +} diff --git a/src/common/hidenan.js b/src/common/hidenan.js new file mode 100644 index 0000000..b42789c --- /dev/null +++ b/src/common/hidenan.js @@ -0,0 +1,9 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +module.exports = function (value) { + if (isNaN(value)) { + return ''; + } else { + return value; + } +} diff --git a/src/common/milesfield.js b/src/common/milesfield.js new file mode 100644 index 0000000..5d851a9 --- /dev/null +++ b/src/common/milesfield.js @@ -0,0 +1,42 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +let _ = require('lodash'); +let tohhmmss = require('./tohhmmss'); +let hidenan = require('./hidenan'); +let tomiles = require('./tomiles'); +let Status = require('./status'); + +let isIdle = Status.isIdle; +let isPark = Status.isPark; +let isStop = Status.isStop; +let isTow = Status.isTow; + + +module.exports = milesField; +function milesField(item, isKilometers) { + if (item.igd != null ) + return tohhmmss(item.igd); + if (item.idleTime != null) + return tohhmmss(item.idleTime / 1000) + + if (_.isFinite(item.mc) && _.isFinite(item.tm)) { + let mc, tm; + if (!isKilometers) { + mc = tomiles(item.mc); + tm = tomiles(item.tm); + } else { + mc = parseFloat(item.mc).toFixed(1); + tm = parseFloat(item.tm).toFixed(1); + } + + if (mc === 0) + mc = '0.0'; + if (tm === 0) + tm = '0.0'; + + // return mc + "|" + tm; + return tm; + } else { + return ''; + } +} diff --git a/src/common/models/Device.js b/src/common/models/Device.js new file mode 100644 index 0000000..874bb43 --- /dev/null +++ b/src/common/models/Device.js @@ -0,0 +1,23 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +let v = require('validator'); +let _ = require('lodash'); + +let Device = function (data) { + if (data == null) { + data = {}; + } + + _.assign(this, data); + + this.imei = v.toString(data.imei); + this.sim = v.toString(data.sim); + this.phone = v.toString(data.phone); + this.network = v.toString(data.network); + this.activationDate = v.toDate(data.activationDate); + this.active = v.toBoolean(data.active); + this.status = v.toString(data.status); + this.orgid = v.toString(data.orgid); +} + +module.exports = Device; diff --git a/src/common/models/Organization.js b/src/common/models/Organization.js new file mode 100644 index 0000000..0350429 --- /dev/null +++ b/src/common/models/Organization.js @@ -0,0 +1,24 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +let v = require('validator'); +let _ = require('lodash'); + +let Organization = function(data) { + if (data == null) { + data = {}; + } + + _.assign(this, data); + + this.id = v.toString(data.id); + this.name = v.toString(data.name); + this.ein = v.toString(data.ein); + this.address1 = v.toString(data.address1); + this.address2 = v.toString(data.address2); + this.city = v.toString(data.city); + this.state = v.toString(data.state); + this.zip = v.toString(data.zip); + this.country = v.toString(data.country); +} + +module.exports = Organization; diff --git a/src/common/models/User.js b/src/common/models/User.js new file mode 100644 index 0000000..ae835fe --- /dev/null +++ b/src/common/models/User.js @@ -0,0 +1,28 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +let v = require('validator'); +let _ = require('lodash'); + +let User = function (data) { + if (data == null) { + data = {}; + } + + _.assign(this, data); + + this.username = v.toString(data.username); + this.password = v.toString(data.password); + this.email = v.toString(data.email); + this.firstname = v.toString(data.firstname); + this.lastname = v.toString(data.lastname); + this.workphone = v.toString(data.workphone); + this.mobilephone = v.toString(data.mobilephone); + this.fax = v.toString(data.fax); + this.isAdmin = v.toBoolean(data.isAdmin); + this.isOrgAdmin = v.toBoolean(data.isOrgAdmin); + this.orgid = data.orgid; + this.advancedMode = v.toBoolean(data.advancedMode); + this.metric = v.toBoolean(data.metric); +} + +module.exports = User; diff --git a/src/common/models/Vehicle.js b/src/common/models/Vehicle.js new file mode 100644 index 0000000..0df9472 --- /dev/null +++ b/src/common/models/Vehicle.js @@ -0,0 +1,77 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +let v = require('validator'); +let _ = require('lodash'); + +let Vehicle = function (data) { + if (data == null) { + data = { + name: '', + plate: '', + vin: '', + device: '', + orgid: '', + state: '', + vehicleType: '', + odometer: '', + engineHours: '', + installLocation: '', + hookedAsset: '', + document: '', + seat: '', + length: '', + width: '', + height: '', + gvWeight: '', + gcWeight: '', + axies: '', + hazardLevel: '', + navigationKey: '', + navigationNumber: '', + unreadMessagePrompt: '', + disableHos: false, + forceMessageReadStatus: false, + enableAssignedDriverIgnition: false, + enableTollFuelTab: false, + allowCoDriving: false, + driverLoginEnforced: false, + enableFuelSensor: false + }; + } + + _.assign(this, data); + + this.id = v.toString(data.id); + this.name = data.name; + this.device = data.device; + this.orgid = data.orgid; + this.plate = v.toString(data.plate); + this.vin = v.toString(data.vin); + this.state = v.toString(data.state); + this.vehicleType = v.toString(data.vehicleType); + this.odometer = v.toFloat(data.odometer); + this.engineHours = v.toFloat(data.engineHours); + this.installLocation = v.toString(data.installLocation); + this.hookedAsset = v.toString(data.hookedAsset); + this.document = v.toString(data.document); + this.seat = v.toString(data.seat); + this.length = v.toFloat(data.length); + this.width = v.toFloat(data.width); + this.height = v.toFloat(data.height); + this.gvWeight = v.toFloat(data.gvWeight); + this.gcWeight = v.toFloat(data.gcWeight); + this.axies = v.toFloat(data.axies); + this.hazardLevel = v.toBoolean(data.hazardLevel); + this.navigationKey = v.toBoolean(data.navigationKey); + this.navigationNumber = v.toBoolean(data.navigationNumber); + this.unreadMessagePrompt = v.toBoolean(data.unreadMessagePrompt); + this.disableHos = v.toBoolean(data.disableHos); + this.forceMessageReadStatus = v.toBoolean(data.forceMessageReadStatus); + this.enableAssignedDriverIgnition = v.toBoolean(data.forceMessageReadStatus); + this.enableTollFuelTab = v.toBoolean(data.enableTollFuelTab); + this.allowCoDriving = v.toBoolean(data.allowCoDriving); + this.driverLoginEnforced = v.toBoolean(data.driverLoginEnforced); + this.enableFuelSensor = v.toBoolean(data.enableFuelSensor); +} + +module.exports = Vehicle; diff --git a/src/common/report/types.js b/src/common/report/types.js new file mode 100644 index 0000000..83d60cd --- /dev/null +++ b/src/common/report/types.js @@ -0,0 +1,15 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +module.exports = { + idle: 'Idle Report', + daily: 'Begin Day End Day Report', + mileage: 'Mileage by State Summary Report', + odometer: 'Odometer by State Summary Report', + speed: 'Speed Report', + ignition: 'Ignition Detail Report', + start: 'Start/Stop Detail Report', + summary: 'Vehicle Summary Report', + obd: 'OBD-II Status Report', + jes: 'OBD-II Engine Report' + // maintenance: 'Maintenance Summary Report', +} diff --git a/src/common/status.js b/src/common/status.js new file mode 100644 index 0000000..eaa7053 --- /dev/null +++ b/src/common/status.js @@ -0,0 +1,228 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import friendlyCommands from '../helper/friendlycommands.js'; +import moment from 'moment'; + +export function isIdle(item) { + return item != null && getStatus(item) === 'Idling'; +} +export function isPark(item) { + return item != null && getStatus(item) === 'Parked'; +} +export function isStop(item) { + return item != null && (item.statusOverride === 'Stopped' || getStatus(item) === 'Stopped'); +} +export function isStart(item) { + return item != null && (item.statusOverride === 'Start' || getStatus(item) === 'Start'); +} +export function isTow(item) { + return item != null && getStatus(item) === 'Towing'; +} +export function isMoving(item) { + return item != null && getStatus(item) === 'Moving'; +} +export function isSpeeding(item) { + return item != null && getStatus(item) === 'Speeding'; +} +export function isHarsh(item) { + return item != null && item.cmd === 'HBM'; +} +export function getStatus(item, ignoreOverride) { + if (!item) { + return ''; + } + const cmd = item.cmd; + if (cmd == null) { + return ''; + } + + if (ignoreOverride !== true && item.statusOverride != null) { + return item.statusOverride; // allow creating start, stopped, etc. + } + + if (cmd === 'FRI') { + if (item.faketow === true) { + return 'Fake Towing'; + } + if (item.ig == null || item.ig === '?') { + if (item.mo) { + return 'Sensor Motion'; + } else { + return 'Sensor Rest'; + } + } + + if (item.ig && !item.mo) { + if (item.mc > 0) { + return 'Moving' + } else { + return 'Idling'; + } + } + if (item.ig && item.mo) { + return 'Moving'; + } + if (!item.ig && item.mo) { + return 'Towing (FRI)'; // We only display Towing Alarm as "Towing". + } + if (!item.ig && !item.mo) { + return 'Parked'; + } + return 'Unknown FRI'; + } else if (cmd === 'GSS') { + if (item.gss) { + return 'GPS seeing ' + item.satelliteNumber + ' satellites'; + } else { + return 'GPS lost'; + } + } else { + if (cmd === 'IGN') { // ignition on + // return friendlyCommands[cmd] + ' after ' + moment.duration(item.igd, 'seconds').humanize() + ' off'; + // return 'Ignition off for ' + moment.duration(item.igd, 'seconds').humanize(); + // return 'Ignition on ' + moment.duration(-item.igd, 'seconds').humanize(true); + // return 'Ignition on; was off ' + moment.duration(-item.igd, 'seconds').humanize(); + return 'Ign on'; + } + if (cmd === 'IGF') { + // return friendlyCommands[cmd] + ' after ' + moment.duration(item.igd, 'seconds').humanize() + ' on'; + // return 'Ignition off; was on ' + moment.duration(item.igd, 'seconds').humanize(); + // return 'Ignition off ' + moment.duration(-item.igd, 'seconds').humanize(true); + return 'Ign off'; + } + if (cmd === 'HBM') { + if (item.rid == null || item.rty == null) { + return 'Harsh behavior'; + } + + let speed; + if (item.rid == '3') { + speed = 'high'; + } else if (item.rid == '2') { + speed = 'medium'; + } else if (item.rid == '1') { + speed = 'low'; + } else { + speed = 'unknown'; + } + + return 'Harsh ' + (item.rty == '1' ? 'accel' : 'brake') + ' (' + speed + ' speed)'; + } + + if (cmd == 'DOG') { + if (!item.rty) { + return friendlyCommands[cmd]; + } + + let type = item.rty; + if (type == 1) + return 'Watchdog reboot (timed)'; + if (type == 2) + return 'Watchdog reboot (ign on)'; + if (type == 3) + return 'Watchdog reboot (input triggered)'; + if (type == 4) + return 'Watchdog reboot (GSM)'; + if (type == 5) + return 'Watchdog reboot (GPRS)'; + else return 'Watchdog reboot'; + } + + + if (friendlyCommands[cmd]) { + return friendlyCommands[cmd]; + } else { + return cmd; + } + // if (cmd === 'IGF') { + // return 'Ign off' + // } else if (cmd === 'STR') { + // return 'Start' + // } else if (cmd === 'STP') { + // return 'Stop' + // } else if (cmd === 'DOG') { + // return 'Dog' + // } else { + // return cmd; + // } + } + +} + +export function isStationaryStatus(item) { + let s = getStatus(item); + return s.indexOf('Idling') > -1 || s.indexOf('Parked') > -1; +} + +export function getStatusColor(item) { + let status = getStatus(item); + + if (isTow(item)) { + return 'orange'; + } + if (isMoving(item) || isStart(item)) { + return 'green'; + } + if (isStop(item)) { + return 'red'; + } + if (isIdle(item)) { + return ' rgb(230, 165, 80)'; + } + if (isSpeeding(item) || isHarsh(item)) { + return '#ff06df' + + } + return ''; +} + +export function getMarkerIconFleetView(item) { + if (isStop(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/red-dot.png'; + } + if (isStart(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/green-dot.png'; + } + if (isMoving(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/green-dot.png'; + } + + if (isTow(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/orange-dot.png'; + } + + if (isIdle(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png'; + } + if (isSpeeding(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/pink-dot.png'; + } + + return 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'; +} + +export function getMarkerIconIndividualHistory(item) { + if (isStop(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/red-dot.png'; + } + if (isStart(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/green-dot.png'; + } + if (isMoving(item)) { + return null; // no markers for moving + } + + if (isTow(item)) { + return null; // no markers for towing + } + + if (isIdle(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png'; + } + + if (isSpeeding(item)) { + return 'http://maps.google.com/mapfiles/ms/icons/pink-dot.png'; + } + + // return 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'; + return null; +} diff --git a/src/common/todir.js b/src/common/todir.js new file mode 100644 index 0000000..5d5dcbb --- /dev/null +++ b/src/common/todir.js @@ -0,0 +1,20 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const _ = require('lodash'); +const windrose = require('windrose'); + +/* Takes azimuth; returns compass direction. */ +module.exports = function (item) { + if (!_.isFinite(item.a)) { + return ''; + } + + let point = windrose.getPoint(item.a, { + depth: 1 + }) + if (!point) { + console.error('bad azimuth on ' + JSON.stringify(item)) + } else { + return point.symbol; + } +} \ No newline at end of file diff --git a/src/common/tohhmmss.js b/src/common/tohhmmss.js new file mode 100644 index 0000000..d7de824 --- /dev/null +++ b/src/common/tohhmmss.js @@ -0,0 +1,20 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +module.exports = function(seconds) { + let sec_num = parseInt(seconds, 10); // don't forget the second param + let hours = Math.floor(sec_num / 3600); + let minutes = Math.floor((sec_num % 3600) / 60); + seconds = Math.floor(sec_num % 60); + + if (hours < 10) { + hours = "0" + hours; + } + if (minutes < 10) { + minutes = "0" + minutes; + } + if (seconds < 10) { + seconds = "0" + seconds; + } + let time = hours + ':' + minutes + ':' + seconds; + return time; +} diff --git a/src/common/tomiles.js b/src/common/tomiles.js new file mode 100644 index 0000000..d0fbd0c --- /dev/null +++ b/src/common/tomiles.js @@ -0,0 +1,12 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +let KilometersToMiles = require("kilometers-to-miles"); +let ktm = new KilometersToMiles(); +let _ = require('lodash'); +module.exports = function (value) { + if (!_.isFinite(value)) { + return ''; + } else { + return parseFloat(ktm.get(value).toFixed(1)); + } +} diff --git a/src/helper/datehelper.js b/src/helper/datehelper.js new file mode 100755 index 0000000..174ebb9 --- /dev/null +++ b/src/helper/datehelper.js @@ -0,0 +1,24 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const regex = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ +/* +Takes a date string like: '20150819141220' +and converts it to a Date object. + +Do something like: +date.toUTCString() +to get as UTC. +*/ +module.exports.toDate = function (dateString) { + const matches = regex.exec(dateString); + + if (matches === null) { + throw new TypeError("'" + dateString + "'" + ' does not look like a valid date.') + } + + if (matches[2] === '00') { // month must be 1 or greater + throw new TypeError('Invalid date string; month must not be 00. Passed string was: ' + dateString) + } + + return new Date(Date.UTC(matches[1],matches[2]-1,matches[3],matches[4],matches[5],matches[6])) +} diff --git a/src/helper/eventreportparser.js b/src/helper/eventreportparser.js new file mode 100755 index 0000000..b690669 --- /dev/null +++ b/src/helper/eventreportparser.js @@ -0,0 +1,390 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +/* +Command: AT+GTXXX=,,...$ +Acknowledgement: +ACK:GTXXX,,,...$ +Report: +RESP:GTXXX,,,...$ +*/ +const datehelper = require('./datehelper'); +const _ = require('lodash'); +const friendlyCommands = require('./friendlycommands'); + +function getFriendlyStatus(status) { + const lookup = '' + status[0] + status[1]; + return friendlyStatus[lookup]; +} + +const friendlyStatus = { // page 128 + '16': 'tow', + '1A': 'fake tow', + '11': 'ignition off rest', + '12': 'ignition off motion', + '21': 'ignition on rest', + '22': 'ignition on motion', + '41': 'sensor rest', + '42': 'sensor motion' +} + +function parseCount(count) { + return parseInt(count, 16) +} + +function getGpsDate(dateInput) { + try { + return datehelper.toDate(dateInput); + } catch (e) { + console.error('bad GPS date ' + dateInput); + return NaN; + } +} + +module.exports = function(commandString) { + // const regexp = new RegExp('^\\+(ACK:GT|RESP:GT)(\\w*)(?:,(\\w*))*?(?:\\$$)') + // const r = /\+(ACK:GT|RESP:GT)(\w*)(?:,(\w*))*?(?:\$)/ + + commandString = commandString.toString('ascii').trim(); + + const regex = /\+(ACK:GT|RESP:GT|BUFF:GT)(\w{3}),(.*)(?:\$)/ + const f = regex.exec(commandString); + + const type = f[1]; + const cmd = f[2]; + const args = f[3].split(','); + + let o = Object.create(null); // output object to return. + o.type = type; + + if (type.startsWith('ACK')) { + o.shorttype = 'ACK'; + } else if (type.startsWith('RESP')) { + o.shorttype = 'RESP'; + } else if (type.startsWith('BUFF')) { + o.shorttype = 'BUFF'; + } else { + throw new Error('Unknown message type: ' + type); + } + + o.cmd = cmd; + o.friendly = friendlyCommands[cmd]; + o.args = args; + + const protocolVersion = args[0].substring(0,2); + if (protocolVersion == '36' && o.shorttype !== 'ACK') { + // TODO check all protocol versions + // check for VIN in GV500 messages and then splice it so it matches up with GV300 order of args + // GV500 has VIN as 3rd argument of RESP messages. (protocol version, unique ID, VIN, device name) + o.vin = args[2]; + args.splice(2, 1); + } + + function loadGPSandGSMdata(startingPosition) { + return loadGSMdata(loadGPSdata(startingPosition)); + } + + // load commonly 11 long block of GPS data & cell data + function loadGPSdata(startingPosition) { + let i = startingPosition; + o.accuracy = Number.parseFloat(args[i++]); + o.speed = Number.parseFloat(args[i++]); + o.azimuth = Number.parseFloat(args[i++]); + o.altitude = Number.parseFloat(args[i++]); + o.longitude = Number.parseFloat(args[i++]); + o.latitude = Number.parseFloat(args[i++]); + o.gpsdate = getGpsDate(args[i++]); // can be NaN + + return i; // returns ending position + } + + function loadGSMdata(startingPosition) { + let i = startingPosition; + o.mcc = args[i++]; + o.mnc = args[i++]; + o.lac = args[i++]; + o.cellid = args[i++]; + i++; // reserved + + return i; // returns ending position + } + + // load commonly 11 long block of GPS data & cell data + // function loadGPSdataBackwardFromEnd(startingPosition) { + // let i = startingPosition; + // o.cellid = args[i--]; + // o.lac = args[i--]; + // o.mnc = args[i--]; + // o.mcc = args[i--]; + // o.gpsdate = getGpsDate(args[i--]); // can be NaN + // o.latitude = Number.parseFloat(args[i--]); + // o.longitude = Number.parseFloat(args[i--]); + // o.altitude = Number.parseFloat(args[i--]); + // o.azimuth = Number.parseFloat(args[i--]); + // o.speed = Number.parseFloat(args[i--]); + // o.accuracy = Number.parseFloat(args[i--]); + // return i; // returns ending position + // } + // load OBD data + function loadOBDdata(startingPosition) { + function bit(x) { + return 1 << x; + } + let i = startingPosition; + const obd = Object.create(null); + o.obd = obd; + const reportMask = o.reportMask; + + if (reportMask & bit(0)) { + obd.vin = args[i++]; + } + if (reportMask & bit(1)) { + obd.connect = args[i++] === '1'; + } + if (reportMask & bit(2)) { + obd.powermV = Number.parseInt(args[i++]); + } + if (reportMask & bit(3)) { + obd.supportPIDs = args[i++]; + } + if (reportMask & bit(4)) { + obd.RPMs = Number.parseInt(args[i++]); + } + if (reportMask & bit(5)) { + obd.speed = Number.parseInt(args[i++]); + } + if (reportMask & bit(6)) { + obd.temp = Number.parseInt(args[i++]); + } + if (reportMask & bit(7)) { + obd.fuelConsumption = Number.parseFloat(args[i]); + if (args[i] === 'inf') obd.fuelConsumption = Infinity; + i++; + } + if (reportMask & bit(8)) + obd.DTCsClearedDistanceOverVehicleTotalMileage = Number.parseFloat(args[i++]); + + if (reportMask & bit(9)) + obd.malfunctionActivatedDistance = Number.parseFloat(args[i++]); + + if (reportMask & bit(10)) + obd.malfunction = args[i++] === '1'; + + if (reportMask & bit(11)) { + // console.log("DTC: " + args[i]); + obd.diagnosticTroubleCodesCount = Number.parseInt(args[i++]); + } + + obd.diagnosticTroubleCodes = []; + + if (Number.parseInt(o.version) >= 360303) { + // So far I have seen versions '360303' and '360402'. + if (reportMask & bit(12)) { + const codes = args[i]; + obd.diagnosticTroubleCodes = codes.match(/.{1,4}/g); + i++; + } + } else { + if (reportMask & bit(12)) { + let codeCount = obd.diagnosticTroubleCodesCount; + if (_.isNaN(codeCount)) { + codeCount = 0; + i++; + } else { + // console.log("# of DTCs: " + codeCount); + if (codeCount > 0) { + for (let j = 0; j < codeCount; j++, i++) { + if (args[i] && args[i] !== '') { + const str = new String(args[i]); + if (str.length === 4) { + obd.diagnosticTroubleCodes.push(args[i]); + } else { + console.error('Error parsing OBD codes, count: ' + codeCount + ' ' + args[i] + ' ' + JSON.stringify(obd.diagnosticTroubleCodes)); + break; + } + } + } + } else { + i += codeCount + 1; + } + } + } + } + + if (reportMask & bit(13)) + obd.throttlePosition = Number.parseInt(args[i++]); + if (reportMask & bit(14)) + obd.engineLoad = Number.parseInt(args[i++]) + if (reportMask & bit(15)) + obd.fuelLevelInput = Number.parseInt(args[i++]); + if (reportMask & bit(19)) // OBD Mileage + obd.mileage = Number.parseFloat(args[i++]); + + if (reportMask & bit(20)) // GPS info + i = loadGPSdata(args.length - 15); + + if (reportMask & bit(21)) // GSM info + i = loadGSMdata(args.length - 8); + + if (reportMask & bit(22)) { // total mileage + o.mileage = Number.parseFloat(args[args.length - 3]); + } + + console.log(JSON.stringify(obd, null, 2)); + + // start of OBD weirdness.. seems an extra field comes in...messages not matching documentation + // if (obd.diagnosticTroubleCodesCount > 0) + // // i += obd.diagnosticTroubleCodesCount + 1; + // i += obd.diagnosticTroubleCodesCount - 1; + // else { + // i++ + // } + // end weirdness + + return i; // returns ending position + } + function loadReportIDandType(item) { + o.rid = item[0]; // report ID + o.rty = item[1]; // report Type + } + + const length = args.length; + o.version = args[0]; // protocol version + o.imei = args[1]; + o.name = args[2]; + o.count = parseCount(args[length - 1]); // count is always the last argument + o.senddate = datehelper.toDate(args[length - 2]); // senddate is always the 2nd to last argument + + if (o.shorttype === 'ACK') { + // TODO special handling for ACK, right now we just save it on the device + } else if (cmd === 'OBD') { + // OBD2 data + o.rty = args[3]; // report Type. 0 = periodic, 1 = GTORR requested + o.reportMask = Number.parseInt(args[4], 16); + o.obd = Object.create(null); + let i = loadOBDdata(5); + // i = loadGPSdata(i) // 23 through 33 + // i++; // reserved + // loadGPSdataBackwardFromEnd(args.length - 5); + // o.mileage = Number.parseFloat(args[args.length - 3]); + } else if (cmd === 'OSM') { + // OBD2 data + o.rid = args[3]; + o.rty = args[4]; // report Type. 0 = periodic, 1 = GTORR requested + o.reportMask = Number.parseInt(args[5], 16); + let i = loadOBDdata(6); + // loadGPSdataBackwardFromEnd(args.length - 5); + // i = loadGPSdata(i); // 23 through 33 + // i++; // reserved + // args[34] reserved + // o.mileage = Number.parseFloat(args[args.length - 3]); + } else if (_.includes(['PNA', 'PFA', 'PDP', 'HBD', 'STC'], cmd)) { + // handled by above. + } else if (_.includes(['MPN', 'MPF', 'BTC', 'JDR'], cmd)) { // main power on, main power off, battery starts charging + let i = loadGPSandGSMdata(3) // 3 through 13 + // args[14] reserved + } else if (_.includes(['TOW', 'DIS', 'IOB', 'SPD', 'SOS', 'RTL', 'DOG', 'IGL', 'HBM'], cmd)) { // 3.3.1. Position Related Report + // args[3] is reserved + loadReportIDandType(args[4]) + o.number = args[5]; + let i = loadGPSandGSMdata(6); // 6 through 17 + o.mileage = Number.parseFloat(args[18]); + } else if (cmd === 'FRI') { // fixed report + o.powervcc = args[3]; + loadReportIDandType(args[4]); + o.number = args[5]; + let i = loadGPSandGSMdata(6); // 6 through 17 + o.mileage = Number.parseFloat(args[18]); + o.hourmeter = args[19]; + o.ain1 = args[20]; + o.ain2 = args[21]; + o.batteryPercent = Number.parseFloat(args[22]); + o.status = args[23]; + // args[24] reserved + // args[25] reserved + // args[26] reserved + } else if (cmd === 'STT') { // + loadReportIDandType(args[3]); + let i = loadGPSandGSMdata(4); // 4 through 15 + } else if (cmd === 'IGN' || cmd === 'IGF') { // ignition on, ignition off + if (cmd === 'IGN') { + o.ignitionDuration = Number.parseFloat(args[3]); + } + if (cmd === 'IGF') { + o.ignitionDuration = Number.parseFloat(args[3]); + } + let i = loadGPSandGSMdata(4); // 4 through 15 + o.hourmeter = args[16]; + o.mileage = Number.parseFloat(args[17]); + } else if (_.includes(['STR', 'STP', 'LSP'], cmd)) { // start / stop etc page 234 + // args[3] reserved + // args[4] reserved + let i = loadGPSandGSMdata(5); // 5 through 16 + o.mileage = Number.parseFloat(args[17]); + } else if (cmd === 'EPS') { // POWER low alarm, page 131 + o.externalPower = args[3]; // 0-32000mV / 0-16000mV + o.inputVcc = args[4]; + loadReportIDandType(args[5]) + o.number = args[6]; + + // TODO I think this may be wrong in the manual. accuracy looks more like speed, here. + // o.accuracy = Number.parseFloat(args[7]); + o.speed = Number.parseFloat(args[7]); + o.azimuth = Number.parseFloat(args[8]); + o.altitude = Number.parseFloat(args[9]); + o.longitude = Number.parseFloat(args[10]); + o.latitude = Number.parseFloat(args[11]); + // o.gpsdate = datehelper.toDate(args[12]); + o.gpsdate = getGpsDate(args[12]); + o.mcc = args[13]; + o.mnc = args[14]; + o.lac = args[15]; + o.cellid = args[16]; + // args[17] reserved + o.mileage = Number.parseFloat(args[18]); + } else if (cmd === 'GSS') { // gps signal lost, page 233 + o.gpsSignalStatus = args[3]; // 0-1 + o.satelliteNumber = args[4]; // 0-24 + o.deviceState = args[5]; + // args[6]; // reserved + let i = loadGPSandGSMdata(7); // 7 through 18 + } else if (cmd === 'OPN' || cmd === 'OPF') { + //gv500 OBDC 2 + let i = loadGPSandGSMdata(3); // 3 through 14 + } else if (cmd === 'INF') { + //todo + o.version = args[0]; // protocol version + o.imei = args[1]; + o.senddate = datehelper.toDate(args[23]); + o.count = parseCount(args[24]); + } else if (cmd === 'GSM') { + //TODO + // o.version = args[0]; // protocol version + // o.imei = args[1]; + o.fixtype = args[2]; + o.mcc1 = args[3]; + o.mnc1 = args[4]; + o.lac1 = args[5]; + o.cellid1 = args[6]; + // o.senddate = datehelper.toDate(args[45]); + // o.count = parseCount(args[46]); + } else if (cmd === 'JES') { + o.jes = Object.create(null); + let jes = o.jes; + jes.reportMask = Number.parseInt(args[3], 16); + jes.journeyConsumption = Number.parseInt(args[4]); + jes.maxRPM = Number.parseInt(args[5]); + jes.averageRPM = Number.parseInt(args[6]); + jes.maxThrottlePosition = Number.parseInt(args[7]); + jes.averageThrottlePosition = Number.parseInt(args[8]); + jes.maxEngineLoad = Number.parseInt(args[9]); + jes.averageEngineLoad = Number.parseInt(args[10]); + loadGPSdata(11); + o.mileage = Number.parseFloat(args[23]); + } else { + console.error('Unknown Command: ' + commandString) + } + + if (o.status) { + o.friendlyStatus = getFriendlyStatus(o.status); + } + + return o; +} diff --git a/src/helper/friendlycommands.js b/src/helper/friendlycommands.js new file mode 100644 index 0000000..79612d7 --- /dev/null +++ b/src/helper/friendlycommands.js @@ -0,0 +1,74 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +module.exports = { + AIS: 'Analog input voltage low alarm', + ANT: 'GPS antenna', + BPL: 'Backup battery low', + BSI: 'Bearer Setting Information', + BTC: 'Backup battery started charging', + CAN: 'Canbus information report', + CFG: 'Global Config', + CRA: 'Crash detection', + DAT: 'Transparent data transmission', + DIS: 'Digital inputs changed', + DOG: 'Protocol watchdog reboot', + DOS: 'Wave shape', + EMG: 'Emergency report mode', + EPS: 'External power supply voltage low', + ERI: 'Temperature sensor report', + FLA: 'Unusual fuel consuption', + FRI: 'Fixed report', + FSD: 'Digital fuel sensor report', + GEO: 'Geofence', + GIN: 'Entered geofence', + GOT: 'Left geofence', + GSM: 'GSM report', + GSS: 'GPS signal status', + HBD: 'Heartbeat', + HBM: 'Harsh acceleration or braking', + HMC: 'Hour meter counter', + IDA: 'iButton information report', + IDF: 'Idling off', + IDN: 'Excessive idling', + IDL: 'Excessive idling', + IGF: 'Ignition off', + IGL: 'Ignition location', + IGN: 'Ignition on', + INF: 'Device information report', + IOB: 'IO combination is set', + JES: 'Engine Info', + JDC: 'Jamming detection', + JDR: 'Jamming detected', + JDS: 'Jamming stopped', + LBC: 'Location by call', + LSP: 'Long stop', + MON: 'Stealthy voice monitoring', + MPF: 'Power disconnected', + MPN: 'Power connected', + PDP: 'GPRS connection', + PDS: 'Preserve special device logical state', + PFA: 'Power off', + PNA: 'Power on', + RTL: 'Manually requested position report', + SOS: 'SOS', + SPD: 'Speeding', + SSR: 'Start stop report', + STC: 'Backup battery stopped charging', + STP: 'Stop Alarm', + STR: 'Start Alarm', + STT: 'Motion Alarm', + TMA: 'Time adjustment', + TMP: 'Temperature', + TOW: 'Towing', + OBD: 'OBD-II status', + OPN: 'OBD-II power on', + OPF: 'OBD-II power off', + ORR: 'OBD-II real-time request', + OSM: 'OBD-II status monitor', + OWH: 'Outside working hours', + PIN: 'Auto-unlock PIN', + QSS: 'Quick Start Setting', + RTO: 'Real-time operation', + SRI: 'Server Register Information', + WLT: 'White list' +} diff --git a/src/helper/reversegeo.js b/src/helper/reversegeo.js new file mode 100644 index 0000000..f16a3e6 --- /dev/null +++ b/src/helper/reversegeo.js @@ -0,0 +1,60 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import Promise from 'bluebird'; +import fetch from 'node-fetch'; +import querystring from 'querystring'; +import {GOOGLE_API_KEY, PROVIDER} from '../../config/geocoding'; +import LRU from 'lru-cache'; +import VError from 'verror'; + +const geoCache = LRU({ + max: 10000, + maxAge: 1000 * 60 * 60 * 24 * 30 /* in ms */ +}); +const httpAdapter = 'https'; + +// optional +const extra = { + apiKey: GOOGLE_API_KEY, // for Mapquest, OpenCage, Google Premier + formatter: null // 'gpx', 'string', ... +}; + +const Geocoder = (async function () { + if (PROVIDER === 'local') { + const geocoder = Promise.promisifyAll(require('local-reverse-geocoder')); + await geocoder.initAsync({ + load: {admin1: true, admin2: false, admin3And4: false, alternateNames: false} + }); + return geocoder; + } else { + return require('node-geocoder')(PROVIDER, httpAdapter, extra); + } +})(); + +export default async function reverseGeo (lat, lng, timeout, force) { + const geocoder = await Geocoder; + if (PROVIDER === 'local') { + const result = (await geocoder.lookUpAsync({ + latitude: lat, + longitude: lng + }, 1))[0][0]; + console.log(JSON.stringify(result, null, 2)); + return result; + } + + if (!force) { + const hit = geoCache.get(lat +','+lng); + if (hit) { + return Promise.resolve(hit); + } + } + + const result = await geocoder.reverse({lat:lat, lon:lng}) + if (result && result.length) { + const r = result[0]; + geoCache.set(lat +','+lng, r); + return r; + } else { + throw new VError('Unexpected reverse geocode', result); + } +} diff --git a/src/listen/.gitignore b/src/listen/.gitignore new file mode 100644 index 0000000..1f9f406 --- /dev/null +++ b/src/listen/.gitignore @@ -0,0 +1 @@ +*built* diff --git a/src/listen/decimaltohex.js b/src/listen/decimaltohex.js new file mode 100644 index 0000000..159be79 --- /dev/null +++ b/src/listen/decimaltohex.js @@ -0,0 +1,14 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +function decimalToHex(d, padding) { + let hex = Number(d).toString(16); + padding = typeof(padding) === "undefined" || padding === null ? padding = 2 : padding; + + while (hex.length < padding) { + hex = "0" + hex; + } + + return new String(hex).toUpperCase(); +} + +module.exports = decimalToHex; diff --git a/src/listen/getv.js b/src/listen/getv.js new file mode 100644 index 0000000..62dceff --- /dev/null +++ b/src/listen/getv.js @@ -0,0 +1,13 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +const Promise = require('bluebird'); +const r = require('./db'); +Promise.coroutine(function*() { + + let vehicle = (yield r.table('vehicles').filter({ + 'device': 'asdf' + }))[0]; + + debugger + +})(); diff --git a/src/listen/listen.js b/src/listen/listen.js new file mode 100644 index 0000000..23728bf --- /dev/null +++ b/src/listen/listen.js @@ -0,0 +1,315 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import Promise from 'bluebird'; +Promise.longStackTraces(); +import reversegeo from '../helper/reversegeo'; +import bunyan from 'bunyan'; +import moment from 'moment'; +import r from '../common/db'; +import {isNaN, isFinite} from 'lodash'; +import {port, host, sack, geocode, insertrawevents} from '../../config/listener.js'; +import { isNotVerbose} from '../common/helpers'; +import os from 'os'; +import dgram from 'dgram'; +import parse from '../helper/eventreportparser'; +import fetch from 'node-fetch'; +import Status from '../common/status'; +import querystring from 'querystring'; +import LRU from 'lru-cache'; +import decimalToHex from './decimaltohex'; +import verror from 'verror'; + +const socket = dgram.createSocket('udp4'); +const vehicleCache = LRU(); +const log = bunyan.createLogger({ + name: 'listen', + // level: 'debug' +}); + +let inserts = 0; +let cachehit = 0; +let concurrent = 0; +let outstandingInserts = {}; + +(async function() { + let cursor = await r.table('vehicles').pluck(['id', 'device']).changes({includeInitial: true}).run(); + cursor.each(function (nothing, changes) { + if (changes) { + log.debug(changes); + let oldVal = changes.old_val; + let newVal = changes.new_val; + + if (oldVal != null && oldVal.device != null) { + vehicleCache.del(oldVal.device); + } + if (newVal != null) { + if (oldVal == null && newVal.device != null) { + vehicleCache.set(newVal.device, newVal); + } else if (newVal.device != null) { + vehicleCache.set(newVal.device, newVal); + } else { + log.debug('No IMEI for vehicle ' + newVal.name + ' ' + newVal.id); + } + } + } + }) + + await reversegeo(45, 45); // Warm up the reverse geocoder + + log.info('Binding to ' + port + ' on host ' + host); + socket.bind(port, host); + + if (process.getuid() === 0) { // if we are root + // we have opened the sockets, now drop our root privileges + process.setgid('nobody'); + process.setuid('nobody'); + // Newer node versions allow you to set the effective uid/gid + if (process.setegid) { + process.setegid('nobody'); + process.seteuid('nobody'); + } + } +})(); + +function sendSack(parsed, remote) { + let msg; + if (parsed.cmd === 'HBD') { + msg = '+SACK:GTHBD' + ',,' + decimalToHex(parsed.count, 4) + '$'; + } else { + msg = '+SACK:' + decimalToHex(parsed.count, 4) + '$'; + } + msg = msg.toUpperCase(); + socket.send(msg, 0, msg.length, remote.port, remote.address); +} + +function deleteNonFiniteValues(obj) { + Object.keys(obj).forEach(function (key) { + // delete NaNs/Infinity as RethinkDB will reject them + if (isNaN(obj[key])) { + delete obj[key]; + } + if (Infinity == obj[key] || -Infinity == obj[key]) { + delete obj[key]; + } + }) +} + +socket.on('listening', function() { + let address = socket.address(); + log.info('UDP Server listening on ' + address.address + ":" + address.port + ' ' + vehicleCache.itemCount + ' vehicles loaded'); +}); + +socket.on('message', async function(message, remote) { + // await lastMessageProcess; + // log.info(remote.address + ':' + remote.port +' - ' + message); + // await Promise.all(outstandingInserts); // wait for all prior inserts to occur + let parsed; + + try { + parsed = parse(message); + } catch (err) { + let wrapped = new verror.WError(err, 'Error parsing from: ' + remote.address + ':' + remote.port + ' , message: ' + message); + throw wrapped; + } + + if (insertrawevents) { + let raw = r.table('rawevents').insert({ + host: os.hostname(), + remotehost: remote.address, + port: remote.port, + message: message.toString(), + imei: parsed.imei, + date: parsed.senddate, + serverDate: new Date() + }).run(); + } + + // ignore FRI towing events and faketow events + if (false + // parsed.friendlyStatus === 'fake tow' + // || parsed.friendlyStatus === 'ignition off motion' + ) { + if (sack) { + sendSack(parsed, remote); + } + return; + } + + const deviceUpdate = Object.create(null); + let isDeviceUpdateOnly = false; + if (isFinite(parsed.batteryPercent)) { + deviceUpdate.batteryPercent = parsed.batteryPercent; + } + + // Device config type messages + if (parsed.cmd === 'HBD') { + deviceUpdate.lastHeartbeat = new Date(); + isDeviceUpdateOnly = true; + } else if (parsed.shorttype === 'ACK' || ['PDP', 'INF', 'CFG', 'GSM', 'VER', 'ALL'].indexOf(parsed.cmd) > -1) { + if (parsed.shorttype === 'ACK') { + deviceUpdate['lastACK' + parsed.cmd] = parsed.senddate; + } else { + deviceUpdate['last' + parsed.cmd] = parsed; + } + isDeviceUpdateOnly = true; + } + + await r.table('devices').get(parsed.imei).update(deviceUpdate).run(); + + if (isDeviceUpdateOnly) { + if (sack) { + sendSack(parsed, remote); + } + return; + } + + // r.db('agilegps').table('events').orderBy({index: r.desc('order')}) + // let result = await r.table('events').insert({ // processed events + // host: remote.address, + // port: remote.port, + // message: message.toString(), + // date: parsed.senddate, + // friendly: parsed.friendly, + // parsed: parsed, + // count: parsed.count + // }); + + // find if associated vehicle and insert vehicle events. + const vehicle = vehicleCache.get(parsed.imei); + + if (vehicle == null) { + throw new Error('Null or undefined vehicle for IMEI ' + parsed.imei); + } + + let toInsert = Object.create(null); + + toInsert.a = parsed.azimuth; + toInsert.b = parsed.shorttype === 'BUFF'; + toInsert.bp = parsed.batteryPercent; + // toInsert.c = parsed.count; + toInsert.cmd = parsed.cmd; + toInsert.d = parsed.senddate; + toInsert.g = parsed.accuracy; + // GPS signal status update only + toInsert.gss = parsed.gpsSignalStatus === '1' ? true : undefined; + toInsert.h = parsed.hourmeter; + + // http://momentjs.com/docs/#/parsing/string-format/ + let id = moment.utc(parsed.senddate).format("YYYYMMDDHHmmssSSS") + '|' + parsed.imei + '|' + decimalToHex(parsed.count + '', 4); // more space efficient ID but with milliseconds + + toInsert.id = id; + toInsert.igd = parsed.ignitionDuration; + toInsert.la = parsed.latitude; + toInsert.lo = parsed.longitude; + + toInsert.m = parsed.mileage; + toInsert.p = parsed.powervcc; + toInsert.rid = parsed.rid; // report ID + toInsert.rty = parsed.rty; // report Type + toInsert.s = parsed.speed; + + // GPS signal status update only + toInsert.satelliteNumber = parsed.satelliteNumber; + toInsert.v = parsed.powervcc; + toInsert.vid = vehicle.id; + + toInsert.vin = parsed.vin; + + if (parsed.cmd === 'TOW') { + toInsert.ig = false; + toInsert.mo = true; + } + + switch (parsed.friendlyStatus) { + case 'fake tow': + toInsert.ig = false; + toInsert.mo = true; + toInsert.faketow = true; + break; + case 'ignition off rest': + toInsert.ig = false; + toInsert.mo = false; + break; + case 'ignition off motion': + toInsert.ig = false; + toInsert.mo = true; + break; + case 'ignition on rest': + toInsert.ig = true; + toInsert.mo = false; + break; + case 'ignition on motion': + toInsert.ig = true; + toInsert.mo = true; + break; + case 'sensor rest': + toInsert.mo = false; + break; + case 'sensor motion': + toInsert.mo = true; + break; + } + + // reverse geocode + if (geocode && isFinite(parsed.latitude) && isFinite(parsed.longitude)) { + try { + let address = await reversegeo(parsed.latitude, parsed.longitude); + toInsert.ad = address; + } catch (e) { + log.error(e); + } + } + + // get the last row + // let previous = await r.table('vehiclehistory').filter({vid: toInsert.vid}).limit(1); + + // if (Status.isStationaryStatus(previous) && Status.isStationaryStatus(toInsert)) { + // // rolluppable. delete previous + // r.table('vehiclehistory').get(previous.id).delete(); + // } + + // delete NaNs/Infinity as RethinkDB will reject them + deleteNonFiniteValues(toInsert); + + // has to happen after deleteNonFiniteValues, otherwise "TypeError: Cannot convert object to primitive value" + if (parsed.jes != null) { + toInsert.jes = parsed.jes; + deleteNonFiniteValues(toInsert.jes); + } + + const vehicleUpdate = { + deviceBatteryPercent: toInsert.bp, + }; + + if (parsed.obd) { + const obd = parsed.obd; + deleteNonFiniteValues(obd); + toInsert.obd = obd; + vehicleUpdate.obd = obd; + } + + if (isNotVerbose(toInsert)) { + // If incoming is not verbose, change the lastVerbose and "last" properties + vehicleUpdate.last = toInsert; + vehicleUpdate.lastVerbose = toInsert; + } else { + // If incoming is verbose, only change the lastVerbose, but not "last" property + vehicleUpdate.lastVerbose = toInsert; + } + + const replacerObj = Object.create(null); + Object.keys(vehicleUpdate).forEach(function (key) { + replacerObj[key] = true; + }); + + await r.table('vehicles').get(vehicle.id).replace(function(vehicle) { + return vehicle.without(replacerObj) + }); + + await r.table('vehicles').get(vehicle.id).update(vehicleUpdate); + await r.table('vehiclehistory').insert(toInsert); + + if (sack) { + sendSack(parsed, remote); + } +}); diff --git a/src/server/.gitignore b/src/server/.gitignore new file mode 100644 index 0000000..1f9f406 --- /dev/null +++ b/src/server/.gitignore @@ -0,0 +1 @@ +*built* diff --git a/src/server/lib/app.js b/src/server/lib/app.js new file mode 100644 index 0000000..826aa87 --- /dev/null +++ b/src/server/lib/app.js @@ -0,0 +1,93 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {Readable} from 'stream'; +// https://github.com/koajs/koa/blob/v2.x/docs/api/index.md +import Promise from 'bluebird'; +const adapt = require('koa-adapter-bluebird'); // uses bluebird-co for performance +// const adapt = require('koa-adapter'); +const Koa = require('koa'); +const app = module.exports = new Koa(); +const fs = Promise.promisifyAll(require('fs')); +const config = require('../../../config/web.js'); +const session = require('koa-session'); +const Compress = require('koa-compress'); +const helmet = require('koa-helmet'); +const Morgan = require('koa-morgan'); +const proxy = require('koa-proxy'); +const KoaJwt = require('koa-jwt'); +const Conditional = require('koa-conditional-get'); +const Etag = require('koa-etag'); +const ResponseTime = require('koa-response-time'); +const BodyParser = require('koa-bodyparser'); +const ServeStatic = require('koa-static'); + +if (config.proxy) { + app.use(adapt(proxy({ + host: config.proxy, + match: /^(?!\/api)(?!\/app)/ // ...everything except /api and /app + }))); +} + +app.use(adapt(ResponseTime())); +app.use(adapt(Conditional())); +app.use(adapt(Etag())); +// app.use(Morgan('combined')); + +const koaBunyanLogger = require('koa-bunyan-logger'); +app.use(adapt(koaBunyanLogger())); +app.use(adapt(koaBunyanLogger.requestIdContext())); +app.use(adapt(koaBunyanLogger.requestLogger())); + + +app.use(helmet.frameguard()); +app.use(helmet.xssFilter()); +app.use(helmet.ieNoOpen()); + +app.use(adapt(Compress())); + +app.keys = config.cookieKeys; + +// Signed-cookies session support +// app.use(adapt(session({ +// maxage: null +// }, app))); + +app.use(adapt(BodyParser())); + +// turn errors into a JSON structure +app.use(async (ctx, next) => { + try { + await next(); + } catch (err) { + // some errors will have .status + // however ctx is not a guarantee + if (err != null) { + ctx.status = err.status || 500; + ctx.type = 'application/json'; + ctx.body = JSON.stringify({ + success: false, + message: err.toString() + }) + + // since we handled ctx manually we'll + // want to delegate to the regular app + // level error handling as well so that + // centralized still functions correctly. + ctx.app.emit('error', err, ctx); + } else { + ctx.status = 500; + ctx.type = 'application/json'; + ctx.body = JSON.stringify({ + success: false, + message: 'null error' + }) + // ctx.app.emit('error', new Error('null or undefined error'), ctx); + } + } +}); + +import {router} from './routes/router'; + +app.use(router.routes()); +app.use(router.allowedMethods()); +app.use(adapt(ServeStatic('../../public'))); diff --git a/src/server/lib/dao.js b/src/server/lib/dao.js new file mode 100644 index 0000000..f75f3be --- /dev/null +++ b/src/server/lib/dao.js @@ -0,0 +1,416 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import Promise from 'bluebird'; +import _ from 'lodash'; +import path from 'path'; +import r from '../../common/db'; +import {isHashed, hash} from './password'; + +export async function getUserByID (id) { + return await r.table('users') + .get(id) +} + +/** + * organizations + */ + +export async function getOrganizations () { + return await r.table('organizations').orderBy('name'); +}; + +export async function getOrganization (id) { + return await r.table('organizations').get(id); +} + +export async function updateOrganization (id, body) { + let x = await r.table('organizations').get(id).update(body, {returnChanges: 'always'}); + return x.changes[0].new_val; +} + +export async function newOrganization (body) { + delete body.id; + let x = await r.table('organizations').insert(body, {returnChanges: 'always'}); + return x.changes[0].new_val; +} + +export async function deleteOrganization (id) { + let org = await r.table('organizations').get(id); + + let vehicles = await getVehicles(id); + + if (vehicles.length > 0) { + throw new Error('Organization contains vehicles; refusing to delete.'); + } + + let users = await getVehicles(id); + + if (users.length > 0) { + throw new Error('Organization contains users; refusing to delete.'); + } + + await r.table('fleets').filter({orgid: id}).delete(); + await r.table('organizations').get(id).delete(); + return {}; +} +/** + * Users + */ + +export async function getUsers (orgid) { + let query = r.table('users').orderBy('username'); + if (orgid != null) { + query = query.filter({ + orgid: orgid + }); + } + return await query; +} + +export async function getUserByOrgId (orgid, id) { + const user = await r.table('users').get(id); + if (user.orgid !== orgid) { + throw new Error('orgid mismatch'); + } else { + return user; + } +} +export async function getUser (id) { + return await r.table('users').get(id); +} + +export async function deleteUser (id) { + await r.table('users').get(id).delete(); + return {}; +} + +export async function saveUser (id, body) { + const user = await r.table('users').get(id); + + if (!isHashed(body.password)) { + let hashed = await hash(body.password); + body.password = hashed; + } + + let x; + if (user) { + x = await r.table('users').get(id).update(body, {returnChanges: 'always'}); + } else { + x = await r.table('users').insert(body, {returnChanges: 'always'}); + } + + return x.changes[0].new_val; +} + +export async function updateUserByOrgId (orgid, id, body) { + const user = await r.table('users').get(id); + if (user.orgid !== orgid) { + throw new Error('orgid mismatch'); + } else { + return await saveUser(id, body); + // if (!isHashed(body.password)) { + // let hashed = await hash(body.password); + // body.password = hashed; + // } + // + // let x = await r.table('users').get(id).update(body, {returnChanges: 'always'}); + // return x.changes[0].new_val; + } +} + +export async function getUserByUsername (username, withPassword) { + if (withPassword) { + let user = await r.table('users').filter({username: username}); + return user[0]; + } else { + let user = await r.table('users').without('password').filter({username: username}); + return user[0]; + } +} + + +/** + * Devices + */ + +export async function getDevices (orgid) { + let query = r.table('devices').orderBy('id'); + if (orgid != null) { + query = query.filter({ + orgid: orgid + }); + } + return await query; +} + +export async function getDevice (id, isAdmin, orgid) { + const device = await r.table('devices').get(id); + if (!isAdmin && device.orgid !== orgid) { + throw new Error('orgid mismatch'); + } else { + return device; + } +} + +export async function deleteDevice (id, isAdmin, orgid) { + const device = await r.table('devices').get(id); + if (!isAdmin && device.orgid !== orgid) { + throw new Error('orgid mismatch'); + } + + // remove device ID from existing vehicles + await r.table('vehicles').getAll('1', {index: 'device'}).update({device: null}); + + // delete device itself + await r.table('devices').get(id).delete(); + return {}; +} + +export async function saveDevice (body, id) { + const device = await r.table('devices').get(id); + + let x; + if (device) { + x = await r.table('devices').get(id).update(body, {returnChanges: 'always'}); + } else { + x = await r.table('devices').insert(body, {returnChanges: 'always'}); + } + return x.changes[0].new_val; +} + +export async function saveDeviceByOrgID (body, id, isAdmin, orgid) { + const device = await r.table('devices').get(id); + if (!isAdmin && device.orgid !== orgid) { + throw new Error('orgid mismatch'); + } else { + return await saveDevice(body, id); + } +} + +// export async function newDevice (body, orgid) { +// if (orgid != null && orgid !== body.orgid) { +// throw new Error('orgid mismatch; expected ' + orgid + ', got ' + body.orgid); +// } +// +// let x = await r.table('devices').insert(body, {returnChanges: 'always'}); +// return x.changes[0].new_val; +// }); + + +/** + * Fleets + */ + +export async function getFleets (orgid) { + let query = r.table('fleets').orderBy('name'); + if (orgid != null) { + query = query.filter({ + orgid: orgid + }); + } + return await query; +} + +export async function getFleet (id, isAdmin, orgid) { + const fleet = await r.table('fleets').get(id); + if (!isAdmin && device.orgid !== orgid) { + throw new Error('orgid mismatch'); + } else { + return fleet; + } +} + +export async function newFleet (body, orgid) { + delete body.id; + if (orgid != null && orgid !== body.orgid) { + throw new Error('orgid mismatch; expected ' + orgid + ', got ' + body.orgid); + } + let x = await r.table('fleets').insert(body, {returnChanges: 'always'}); + return x.changes[0].new_val; +} + +export async function updateFleet (body, id, isAdmin, orgid) { + const fleet = await r.table('fleets').get(id); + if (!isAdmin && fleet.orgid !== orgid) { + throw new Error('orgid mismatch'); + } else { + let x = await r.table('fleets').get(id).update(body, {returnChanges: 'always'}); + return x.changes[0].new_val; + } +} + +export async function deleteFleet (id, isAdmin, orgid) { + const fleet = await r.table('fleets').get(id); + if (!isAdmin && fleet.orgid !== orgid) { + throw new Error('orgid mismatch'); + } else { + await r.table('fleets').get(id).delete(); + return {}; + } +} + +/** + * Vehicles + */ + +export async function getVehicles (orgid) { + let query = r.table('vehicles').orderBy('name'); + if (orgid != null) { + query = query.filter({orgid: orgid}); + } + return await query; +} + +export async function getVehicle (orgid, id, isAdmin) { + const vehicle = await r.table('vehicles').get(id); + if (!isAdmin && vehicle.orgid !== orgid) { + throw new Error('orgid mismatch; expected ' + vehicle.orgid + ', got ' + orgid); + } else { + return vehicle; + } +} + +export async function deleteVehicle (orgid, id, isAdmin) { + const vehicle = await r.table('vehicles').get(id); + if (!isAdmin && vehicle.orgid !== orgid) { + throw new Error('orgid mismatch; expected ' + vehicle.orgid + ', got ' + orgid); + } + + // delete vehicle history + await r.table('vehiclehistory').getAll(id, {index:'vid'}).delete(); + + // update fleets + await r.table('fleets').update(function (row) { + return { + vehicles: row('vehicles').filter(function (vehicle) { + return vehicle.ne(id) + }) + } + }) + + // delete vehicle itself + await r.table('vehicles').get(id).delete(); + return {}; +} + +const throwIfIMEIUsed = async function (imei, id) { + if (imei == null || imei == '') return; + let x = await r.table('vehicles').filter({device:imei}); + if (x.length > 1) { + throw new Error('A vehicle is already using IMEI: ' + imei); + } else if (x.length === 1) { + let otherVehicle = x[0] + if (id === otherVehicle.id) { + return; + } + } +} + +export async function updateVehicle (orgid, id, body, isAdmin) { + const vehicle = await r.table('vehicles').get(id); + await throwIfIMEIUsed(body.device, id); + if (body.imei == null) body.imei = ''; + + if (!isAdmin && vehicle.orgid !== orgid) { + throw new Error('orgid mismatch; expected ' + vehicle.orgid + ', got ' + orgid); + } else { + let x = await r.table('vehicles').get(id).update(body, {returnChanges: 'always'}); + return x.changes[0].new_val; + } +} + +export async function newVehicle (orgid, body) { + delete body.id; + await throwIfIMEIUsed(body.device); + if (body.imei == null) body.imei = ''; + + if (orgid !== body.orgid) { + throw new Error('orgid mismatch'); + } + let x = await r.table('vehicles').insert(body, {returnChanges: 'always'}); + return x.changes[0].new_val; +} + +export async function getVehicleHistory (orgid, id, startDate, endDate) { + const vehicle = await getVehicle(orgid, id); + if (vehicle.orgid !== orgid) { + throw new Error('orgid mismatch'); + } + let history = await r.table('vehiclehistory') + .between(startDate, endDate, {index: 'd', leftBound: 'closed', rightBound: 'open'}) + // .getAll(id, {index: 'vid'}) + .filter({'vid': id}) + // .filter(r.row('d').during(r.ISO8601(startDate.toISOString()), r.ISO8601(endDate.toISOString()), {leftBound: "open", rightBound: "closed"})) + .orderBy('id'); + + return history; +} + +/* +--- +0. Initial setup + +r.db('agilegps').table('vehicles').orderBy('name').filter({orgid: 'default'}) +join with +r.db('agilegps').table('vehiclehistory').filter({vid: 'Generated Vehicle 861074021378065'}).orderBy(r.desc('d')).limit(1) + +--- +1. Basic Join: + +r.db('agilegps').table('vehiclehistory').eqJoin('vid', r.db('agilegps').table('vehicles')) + +--- + +2. Filtered Join: + +r.db('agilegps').table('vehicles').orderBy('name').filter({orgid: 'default'}) + +3rd attempt + +r.db('agilegps').table('vehicles').orderBy('name').filter({orgid: 'default'}) + .merge(function (vehicle) { + return r.db('agilegps').table('vehiclehistory').filter({vid: vehicle.id}).orderBy(r.desc('d')).limit(1) + }) + +4th attempt + +r.db('agilegps').table('vehicles').orderBy('name').filter({orgid: 'default'}) + .merge(function (vehicle) { + return r.db('agilegps').table('vehiclehistory').getAll('Generated Vehicle 861074021378065', {index:'vid'}).orderBy(r.desc('d')).limit(1).coerceTo('array') + }) + +5th attempt: + +r.db('agilegps').table('vehicles').orderBy('name').filter({orgid: 'default'}) + .merge(function (vehicle) { + return { + last: r.db('agilegps').table('vehiclehistory').getAll('Generated Vehicle 861074021378065', {index:'vid'}).orderBy(r.desc('d')).limit(1).coerceTo('array') + } + }) + +6th attempt: + +r.db('agilegps').table('vehicles').orderBy('name').filter({orgid: 'default'}).limit(3) + .merge(function (vehicle) { + return { + last: r.db('agilegps').table('vehiclehistory').getAll(vehicle('id'), {index:'vid'}).orderBy(r.desc('d')).limit(1).coerceTo('array') + } + }) + + +*/ +// export async function getAllVehicleStatus (orgid) { +// return r.table('vehicles').orderBy('name').filter({orgid: orgid}) +// // .limit(150) +// // .merge(function (vehicle) { +// // return { +// // last: r.table('vehiclehistory') +// // .getAll(vehicle('id'), {index:'vid'}) +// // .orderBy(r.desc('id')) +// // .limit(1) +// // .coerceTo('array') +// // .nth(0) +// // .default({}) +// // } +// // }) +// } diff --git a/src/server/lib/jwthelper.js b/src/server/lib/jwthelper.js new file mode 100644 index 0000000..32c6b5c --- /dev/null +++ b/src/server/lib/jwthelper.js @@ -0,0 +1,45 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import Promise from 'bluebird'; +import assert from 'assert'; +import JWT from 'jsonwebtoken'; +Promise.promisifyAll(JWT); +import unless from 'koa-unless'; +import {jwtSecret} from '../../../config/web.js'; + +export function jwtSignDefault (obj, options) { + options || {}; + // options.expiresInMinutes = 60; + return JWT.sign(obj, jwtSecret, options); +} + +export function jwtCookie(opts) { + opts = opts || {}; + opts.key = opts.key || 'user'; + assert(opts.secret, '"secret" option is required'); + + const middleware = async function(ctx, next) { + const token = ctx.cookies.get('jwt'); + let user, err; + + try { + user = await JWT.verify(token, opts.secret, opts); + } catch (e) { + err = e; + } + + if (user != null) { + ctx.state = ctx.state || {}; + ctx.state[opts.key] = user; + } + + if (user != null || opts.passthrough) { + await next(); + } else { + ctx.throw(401, err); + } + } + + middleware.unless = unless; + return middleware; +}; diff --git a/src/server/lib/password.js b/src/server/lib/password.js new file mode 100644 index 0000000..8ea2b2f --- /dev/null +++ b/src/server/lib/password.js @@ -0,0 +1,17 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import Promise from 'bluebird'; +import bcrypt from 'bcrypt'; +Promise.promisifyAll(bcrypt); +const rounds = 10; +const hashmatch = /^\$2[ayb]\$.{56}$/ + +export function isHashed(str) { + return hashmatch.test(str); +} + +export async function hash (password) { + const salt = await bcrypt.genSaltAsync(rounds); + const hash = await bcrypt.hashAsync(password, salt); + return hash; +} diff --git a/src/server/lib/reports.js b/src/server/lib/reports.js new file mode 100644 index 0000000..58d4b1d --- /dev/null +++ b/src/server/lib/reports.js @@ -0,0 +1,133 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import Promise from 'bluebird'; +import _ from 'lodash'; +import r from '../../common/db'; +import {get} from 'lodash'; +import bunyan from 'bunyan'; +import moment from 'moment'; +import helpers from '../../common/helpers'; +import {isIdle, isPark, isStop, isTow} from '../../common/status'; +import addressdisplay from'../../common/addressdisplay'; + +import idleReport from './reports/idle'; +import dailyReport from './reports/daily'; +import mileageReport from './reports/mileage'; +import odometerReport from './reports/odometer'; +import startReport from './reports/start'; +import ignitionReport from './reports/ignition'; +import speedReport from './reports/speed'; +import summaryReport from './reports/summary'; +import obdReport from './reports/obd'; +import jesReport from './reports/jes'; + +const log = bunyan.createLogger({ + name: 'reports', + level: 'debug' +}); + +function ignoreCaseEquals(a, b) { + return new RegExp("^" + a + "$", "i").test(b); +} +module.exports.getReport = async function(orgid, reportid, vehicles, startDate, endDate, tzOffset) { + startDate = new Date(startDate); + endDate = new Date(endDate); + + log.debug('Report Start: ' + moment(startDate).utc().format()); + log.debug('Report End: ' + moment(endDate).utc().format()); + + const result = { + query: { + orgid: orgid, + reportid: reportid, + startDate: startDate, + endDate: endDate, + tzOffset: tzOffset, + vehicles: vehicles + }, + vehicles: {}, + results: {}, + totals: {} + } + + await Promise.map(vehicles, async function (vid) { + const vehicle = await r.table('vehicles').get(vid); + if (vehicle.orgid !== orgid) { + // security check each vehicle so end user can't insert any vehicle ID into the request + throw new Error(vid + ' does not exist or you do not have access to it') + } + result.vehicles[vid] = vehicle; + }, { + concurrency: 1 + }); + + await Promise.map(vehicles, async function (vid) { + const history = await r.table('vehiclehistory').between(startDate, endDate, { + index: 'd', + leftBound: 'closed', + rightBound: 'open' + }) + .filter({ + 'vid': vid + }) + .orderBy('id'); + + switch (reportid) { + case 'idle': + const reportResults = idleReport(history); + result.results[vid] = reportResults.results; + result.totals[vid] = reportResults.totals; + break; + + case 'daily': + + result.results[vid] = dailyReport(history, tzOffset); + break; + + case 'mileage': + result.results[vid] = mileageReport(history, result.totals); + break; + + case 'odometer': + result.results[vid] = odometerReport(history); + break; + + case 'start': + result.results[vid] = startReport(history); + break; + + case 'ignition': + result.results[vid] = ignitionReport(history); + break; + + case 'speed': + const threshold = 112.654; // 70 mph + result.results[vid] = speedReport(history, threshold); + result.totals[vid] = _.max(_.map(history, function(item) { + return item.s; + })); + break; + + case 'summary': + result.results[vid] = Object.assign(summaryReport(history), { + name: vid + }); + break; + + case 'obd': + result.results[vid] = obdReport(history); + break; + + case 'jes': + result.results[vid] = jesReport(history); + break; + + default: + throw new Error('Unknown report type ' + reportid); + } + }, { + concurrency: 1 + }); + + return result; +} diff --git a/src/server/lib/reports/daily.js b/src/server/lib/reports/daily.js new file mode 100644 index 0000000..267601b --- /dev/null +++ b/src/server/lib/reports/daily.js @@ -0,0 +1,67 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {get} from 'lodash'; +import bunyan from 'bunyan'; +import moment from 'moment'; +import {cleanData, mileageChange} from '../../../common/helpers'; +import {getStatus} from '../../../common/status'; + +const log = bunyan.createLogger({ + name: 'reports', + // level: 'debug' +}); + +export default (history, tzOffset) => { + let currentDay, firstIgnOn, lastIgnOff, beginOdometer, endOdometer; + function resetDay() { + currentDay = null; + firstIgnOn = null; + lastIgnOff = null; + beginOdometer = NaN; + endOdometer = NaN; + } + + resetDay(); + + return mileageChange(cleanData(history)).reduce((previousValue, currentValue, currentIndex, array) => { + function checkValue() { + let st = getStatus(currentValue); + if (currentDay == null) { + if (st === 'Ign on') { + currentDay = moment(new Date(currentValue.d)).startOf('day'); + currentDay = currentDay.add(tzOffset, 'minutes'); + log.debug('Current day: ' + currentDay.utc().format()) + beginOdometer = currentValue.m; + firstIgnOn = new Date(currentValue.d); + log.debug('First on: ' + moment(firstIgnOn).utc().format()); + } + } + } + checkValue(); + + let isWithinTheDay = currentDay != null && moment(new Date(currentValue.d)).isBefore(moment(currentDay).add('1', 'days')); + + if (getStatus(currentValue) === 'Ign off' && isWithinTheDay) { + lastIgnOff = new Date(currentValue.d); + endOdometer = currentValue.m; + } + + if (currentDay != null && (!isWithinTheDay || currentIndex === array.length - 1)) { + log.debug('Last off: ' + moment(lastIgnOff).utc().format()); + + previousValue.push({ + d: currentDay.toISOString(), + firstIgnOn: firstIgnOn, + lastIgnOff: lastIgnOff, + duration: moment(lastIgnOff).diff(firstIgnOn) / 1000, + beginOdometer: beginOdometer, + endOdometer: endOdometer, + distance: endOdometer - beginOdometer + }) + resetDay(); + checkValue(); + } + + return previousValue; + }, []) +}; diff --git a/src/server/lib/reports/idle.js b/src/server/lib/reports/idle.js new file mode 100644 index 0000000..c7b2c51 --- /dev/null +++ b/src/server/lib/reports/idle.js @@ -0,0 +1,29 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import _ from 'lodash'; +import {get} from 'lodash'; +import bunyan from 'bunyan'; +import Promise from 'bluebird'; +import moment from 'moment'; +import {cleanData, rollup} from '../../../common/helpers'; +import {isIdle} from '../../../common/status'; + +const log = bunyan.createLogger({ + name: 'reports', + level: 'debug' +}); + +export default (history) => { + let result = Object.create(null); + history = cleanData(history); + history = history.filter(item => item.cmd === 'FRI' || item.cmd === 'IGN' || item.cmd === 'IGF'); + history = rollup(history); + history = history.filter(isIdle) + + result.results = history; + result.totals = history.reduce(function(prev, curr) { + return prev + curr.idleTime; + }, 0); + + return result; +} diff --git a/src/server/lib/reports/ignition.js b/src/server/lib/reports/ignition.js new file mode 100644 index 0000000..0403ebd --- /dev/null +++ b/src/server/lib/reports/ignition.js @@ -0,0 +1,78 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import _ from 'lodash'; +import {get} from 'lodash'; +import bunyan from 'bunyan'; +import Promise from 'bluebird'; +import moment from 'moment'; + +import {cleanData, ignitionMileage, mileageChange} from '../../../common/helpers'; + +import {getStatus, isIdle, isPark, isStop, isStart, isTow} from '../../../common/status'; +import addressdisplay from'../../../common/addressdisplay'; + +const log = bunyan.createLogger({ + name: 'reports', + // level: 'debug' +}); + +export default (history) => { + history = cleanData(history); + history = mileageChange(history); + history = ignitionMileage(history); + + history = history.filter(function(item) { + return item.cmd === 'FRI' || item.cmd === 'IGN' || item.cmd === 'IGF'; + }) + + let startTime = null; + let mileageStart = NaN; + let idleDuration = 0; + let parkedStart = null; + let lastStop = null; + + history = history.reduce(function(output, current) { + let last = output[output.length - 1]; + if (current.cmd === 'IGN') { + startTime = current.d; + mileageStart = current.m; + idleDuration = 0; + lastStop = null; + } + + if (isIdle(current) && last != null && current.d != null && startTime != null) { + idleDuration += moment(current.d).diff(last.d) / 1000 + } + + if (startTime != null && current.cmd === 'IGF') { + current.startTime = startTime; + current.startStopMileage = current.m - mileageStart; + current.transitTime = moment(current.d).diff(current.startTime) / 1000; + current.idleDuration = idleDuration; + lastStop = current; + } else if (current.cmd === 'IGF') { + current.startTime = null; + current.startStopMileage = 0; + current.idleDuration = 0; + startTime = null; + mileageStart = current.m; + idleDuration = 0; + lastStop = current; + } + + if (lastStop != null && isPark(current)) { + if (!lastStop.parkedStart) { + lastStop.parkedStart = current.d; + } + lastStop.ad = current.ad; + lastStop.parkedEnd = current.d; + lastStop.parkedDuration = moment(lastStop.parkedEnd).diff(lastStop.parkedStart) / 1000; + } + + output.push(current); + + return output; + }, []) + + return history.filter(item => item.cmd === 'IGF'); +} diff --git a/src/server/lib/reports/jes.js b/src/server/lib/reports/jes.js new file mode 100644 index 0000000..d508eec --- /dev/null +++ b/src/server/lib/reports/jes.js @@ -0,0 +1,3 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +export default history => history.filter(item => item.cmd === 'JES'); diff --git a/src/server/lib/reports/mileage.js b/src/server/lib/reports/mileage.js new file mode 100644 index 0000000..921ff0b --- /dev/null +++ b/src/server/lib/reports/mileage.js @@ -0,0 +1,41 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {isFinite} from 'lodash'; +import {get} from 'lodash'; +import bunyan from 'bunyan'; +import Promise from 'bluebird'; +import moment from 'moment'; +import {cleanData, mileageChange} from '../../../common/helpers'; +import {state as displayState} from '../../../common/addressdisplay'; + +const log = bunyan.createLogger({ + name: 'reports', + // level: 'debug' +}); + +export default (history, totals) => { + history = history.filter(item => item.la != null && item.lo != null); + + history = cleanData(history); + history = mileageChange(history); + + let mileageByState = Object.create(null); + + history.forEach(function(item) { + if (isFinite(item.mc) && item.mc > 0) { + let state = displayState(item) || 'Unknown'; + + if (mileageByState[state] == null) { + mileageByState[state] = 0; + } + if (totals[state] == null) { + totals[state] = 0; + } + + mileageByState[state] += item.mc; + totals[state] += item.mc; + } + }) + + return mileageByState; +} diff --git a/src/server/lib/reports/obd.js b/src/server/lib/reports/obd.js new file mode 100644 index 0000000..d3895e2 --- /dev/null +++ b/src/server/lib/reports/obd.js @@ -0,0 +1,3 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +export default history => history.filter(item => item.cmd === 'OBD' || item.cmd === 'OSM'); diff --git a/src/server/lib/reports/odometer.js b/src/server/lib/reports/odometer.js new file mode 100644 index 0000000..79dd42e --- /dev/null +++ b/src/server/lib/reports/odometer.js @@ -0,0 +1,62 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {isFinite} from 'lodash'; +import {get} from 'lodash'; +import bunyan from 'bunyan'; +import Promise from 'bluebird'; +import moment from 'moment'; +import {cleanData, mileageChange, ignitionMileage} from '../../../common/helpers'; +import {getStatus, isIdle, isPark, isStop, isStart, isTow} from '../../../common/status'; +import {state as displayState} from '../../../common/addressdisplay'; + +const log = bunyan.createLogger({ + name: 'reports', + // level: 'debug' +}); + +export default (history) => { + history = history.filter(function (item) { + return item.la != null && item.lo != null + }) + + history = cleanData(history); + history = mileageChange(history); + history = ignitionMileage(history); + + let odometerStart, odometerEnd; + let mileageByState = []; + let currentState = null; + let firstState = true; + + history.reduce(function(prev, curr, idx, array) { + if (isFinite(curr.m) && curr.m > 0) { + let state = displayState(curr) || 'Unknown'; + + if (state != null && firstState) { + currentState = state; + odometerStart = curr.m; + odometerEnd = curr.m; + firstState = false; + } else if (state != null && state != currentState || idx === array.length - 1) { // hit a new state or the end + odometerEnd = curr.m; + mileageByState.push({ + state: currentState, + odometerStart: odometerStart, + odometerEnd: odometerEnd + }) + + currentState = state; + odometerStart = curr.m; + odometerEnd = curr.m; + + } else { + if (state != null) { + odometerEnd = curr.m; + } + } + } + + }, []) + + return mileageByState; +} diff --git a/src/server/lib/reports/speed.js b/src/server/lib/reports/speed.js new file mode 100644 index 0000000..b0bb4b0 --- /dev/null +++ b/src/server/lib/reports/speed.js @@ -0,0 +1,3 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +export default (history, threshold) => history.filter( item => item.s > threshold); diff --git a/src/server/lib/reports/start.js b/src/server/lib/reports/start.js new file mode 100644 index 0000000..3d0c6de --- /dev/null +++ b/src/server/lib/reports/start.js @@ -0,0 +1,80 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import _ from 'lodash'; +import {get} from 'lodash'; +import bunyan from 'bunyan'; +import Promise from 'bluebird'; +import moment from 'moment'; +import {cleanData, getAccuracy, nullToBlank, onlyVisibleHistory, addStartStop, rollup, ignitionMileage, mileageChange, startStopMileage} from '../../../common/helpers'; +import {getStatus, isIdle, isPark, isStop, isStart, isTow} from '../../../common/status'; + +const log = bunyan.createLogger({ + name: 'reports', + // level: 'debug' +}); + +export default (history) => { + history = cleanData(history); + history = onlyVisibleHistory(history); + history = mileageChange(history); + history = addStartStop(history); + history = startStopMileage(history); + + let startTime = null; + let mileageStart = NaN; + let idleDuration = 0; + let parkedStart = null; + let lastStop = null; + + history = history.reduce(function(output, current) { + let last = output[output.length - 1]; + if (isStart(current)) { + if (last) { + startTime = last.d; // some mileage can occur on the start, so need to grab the event right before it. + mileageStart = last.m; + } else { + startTime = current.d; + mileageStart = current.m; + } + idleDuration = 0; + lastStop = null; + } + + if (isIdle(current) && last != null && current.d != null && startTime != null) { + idleDuration += moment(current.d).diff(last.d) / 1000 + } + + if (startTime != null && isStop(current)) { + current.startTime = startTime; + current.startStopMileage = current.m - mileageStart; + current.transitTime = moment(current.d).diff(current.startTime) / 1000; + current.idleDuration = idleDuration; + lastStop = current; + } else if (isStop(current)) { + current.startTime = null; + current.startStopMileage = 0; + current.idleDuration = 0; + startTime = null; + mileageStart = current.m; + idleDuration = 0; + lastStop = current; + } + + if (lastStop != null && isPark(current)) { + if (!lastStop.parkedStart) { + lastStop.parkedStart = current.d; + } + lastStop.ad = current.ad; + lastStop.parkedEnd = current.d; + lastStop.parkedDuration = moment(lastStop.parkedEnd).diff(lastStop.parkedStart) / 1000; + } + + output.push(current); + + return output; + }, []) + + history = _.filter(history, isStop); + + return history; +} diff --git a/src/server/lib/reports/summary.js b/src/server/lib/reports/summary.js new file mode 100644 index 0000000..4b932f9 --- /dev/null +++ b/src/server/lib/reports/summary.js @@ -0,0 +1,93 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import {isNaN, isFinite} from 'lodash'; +import {get} from 'lodash'; +import bunyan from 'bunyan'; + +import {containsMotionInformation, cleanData, getAccuracy, nullToBlank, onlyVisibleHistory, addStartStop, rollup, ignitionMileage, mileageChange, startStopMileage, isMotion} + from '../../../common/helpers'; + +import {getStatus, isIdle, isPark, isStop, isStart, isTow} from '../../../common/status'; + +const log = bunyan.createLogger({ + name: 'reports', + // level: 'debug' +}); + +export default (history) => { + let result = Object.create(null); + + history = cleanData(history); + history = history.filter(containsMotionInformation) + history = mileageChange(history); + history = ignitionMileage(history); + history = rollup(history); + + let beginOdometer = NaN; + let endOdometer = NaN; + let totalTransit = 0; + + let parks = []; + let idles = []; + + history.reduce((output, current, idx, array) => { + if (isNaN(beginOdometer) && !isNaN(current.m)) { + beginOdometer = current.m; + } + + if (!isNaN(current.m)) { + endOdometer = current.m; + } + + if (getStatus(current) === 'Parked') { + parks.push(current.idleTime); + } + + if (getStatus(current) === 'Idling') { + idles.push(current.idleTime); + } + + let prev = array[idx - 1]; + if (prev && isMotion(current)) { + let dur = (new Date(current.d).valueOf() - new Date(prev.d).valueOf()) / 1000 + totalTransit += dur; + } + }, []) + + let totalIdle = 0; + idles.forEach(function(dur) { + if (isFinite(dur)) { + totalIdle += dur / 1000; + } + }) + + let totalPark = 0; + parks.forEach(function(dur) { + if (isFinite(dur)) { + totalPark += dur / 1000; + } + }) + + let avgIdle = totalIdle / idles.length; + let avgPark = totalPark / parks.length; + + if (!isFinite(avgIdle)) { + avgIdle = 0; + } + if (!isFinite(avgPark)) { + avgPark = 0; + } + + return { + parks: parks.length, + idles: idles.length, + totalIdle: totalIdle, + totalPark: totalPark, + avgIdle: avgIdle, + avgPark: avgPark, + beginOdometer: beginOdometer, + endOdometer: endOdometer, + distance: endOdometer - beginOdometer, + totalTransit: totalTransit + } +} diff --git a/src/server/lib/routes/router.js b/src/server/lib/routes/router.js new file mode 100644 index 0000000..904a806 --- /dev/null +++ b/src/server/lib/routes/router.js @@ -0,0 +1,392 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import Promise from 'bluebird'; +import {mustBeAdmin, mustBeAdminOrOrgAdmin, onlyAdminCanSetAdmin, mustBeAdminOrOrgMember, mustBeObjectOwnerOrAdminOrOrgAdmin} from '../security'; +import Router from 'koa-router'; +import r from '../../../common/db'; +import vehiclestatus from './vehiclestatus'; +import vehiclehistory from './vehiclehistory'; +import KoaJwt from 'koa-jwt'; +import config from '../../../../config/web.js'; +import {jwtSignDefault, jwtCookie} from '../jwthelper'; +import moment from 'moment'; +import reports from '../reports'; +// import reverseGeo from '../../../helper/reversegeo'; +const bcrypt = Promise.promisifyAll(require('bcrypt')); + +const dao = require('../dao'); + +export const router = new Router(); +const adapt = require('koa-adapter-bluebird'); // uses bluebird-co for performance + +const jwtrequired = adapt(new KoaJwt({ + secret: config.jwtSecret, +})); + +const jwtoptional = adapt(new KoaJwt({ + secret: config.jwtSecret, + passthrough: true +})); + +// allow cookie-based JWT, e.g., without Authorization header +// useful for report download links +const jwtcookie = jwtCookie({ + secret: config.jwtSecret, + passthrough: true +}); + +/**** +Login / Logout +***/ +router.get('/api/session', jwtrequired, async function (ctx, next) { + if (ctx.state.user) { + const user = await dao.getUserByUsername(ctx.state.user.username, false /* without password */); + if (!user) { + ctx.status = 401; + return; + } else { + ctx.body = Object.create(null); + ctx.body.user = user; + ctx.body.jwt = jwtSignDefault(user); + } + } else { + ctx.status = 401; + ctx.body = {}; + } +}) + +router.delete('/api/session', async function (ctx, next) { + ctx.session = null; + ctx.status = 204; + ctx.body = {}; +}); + +router.post('/api/session', jwtoptional, async function (ctx, next) { + const rememberMe = ctx.request.body.rememberMe === true; + + if (!ctx.request.username && !ctx.request.body) { + ctx.body = {success: false, message: 'invalid username or password'} + ctx.status = 400; + return; + } + + const user = await dao.getUserByUsername(ctx.request.body.username, true /* with password */); + + if (!user) { + ctx.body = {success: false, message: 'invalid username or password'} + ctx.status = 400; + return; + } + + // if (ctx.request.body.password === user.password) { + if (await bcrypt.compareAsync(ctx.request.body.password, user.password)) { + delete user.password; // dont return the password in the response + const jwt = jwtSignDefault(user); + ctx.cookies.set('jwt', jwt, { + httpOnly: false, + sign: false, + expires: rememberMe ? moment().add(365, 'days').toDate() : null // null == session cookie + // expires: rememberMe ? moment().add(1, 'seconds').toDate() : null // For testing expired cookies + }); + ctx.response.body = Object.create(null); + ctx.response.body.user = user; + ctx.response.body.jwt = jwt; + } else { + ctx.body = {success: false, message: 'invalid username or password'} + ctx.status = 400; + } +}) + +/**** +Events: only admins can acccess. +***/ + +// r.db('agilegps').table('events').orderBy({index: r.desc('order')}) +router.get('/api/events', jwtrequired, mustBeAdmin, async function (ctx, next) { + let events; + if (ctx.query.page && ctx.query.pagesize) { + let page = parseInt(ctx.query.page, 10); + page = page - 1; + let pagesize = parseInt(ctx.query.pagesize, 10); + events = await r.table('vehiclehistory').orderBy({index: r.desc('id')}).slice(page * pagesize + , page * pagesize + pagesize + , {right_bound: 'open'}) + } else { + events = await r.table('vehiclehistory').orderBy({index: r.desc('id')}); + } + ctx.body = events; +}) + +router.get('/api/count/events', jwtrequired, mustBeAdmin, async function (ctx, next) { + const count = await r.table('vehiclehistory').count(); + ctx.body = { + count: count + }; +}) + +const MAX_RAW_EVENTS = 20000; +function getRawEvents(search) { + let events = r.table('rawevents'); + if (search) { + events = events.getAll(search, {index: 'imei'}); + events = events.orderBy(r.desc('date')); + events = events.limit(MAX_RAW_EVENTS); + } else { + events = events.orderBy({index: r.desc('date')}) + events = events.limit(MAX_RAW_EVENTS); + } + return events; +} + +router.get('/api/rawevents', jwtrequired, mustBeAdmin, async function (ctx, next) { + let search = ctx.query.search; + let events = getRawEvents(search); + if (ctx.query.page && ctx.query.pagesize) { + let page = parseInt(ctx.query.page, 10); + page = page - 1; + let pagesize = parseInt(ctx.query.pagesize, 10); + events = events.slice(page * pagesize, page * pagesize + pagesize, {right_bound: 'open'}) + } + ctx.body = await events; +}) + +router.get('/api/count/rawevents', jwtrequired, mustBeAdmin, async function (ctx, next) { + let search = ctx.query.search; + let events = getRawEvents(search); + ctx.body = { + count: await events.count() + }; +}) + +/**** +Exceptions: only admins can acccess. +***/ +// r.db('agilegps').table('events').orderBy({index: r.desc('order')}) +router.get('/api/exceptions', jwtrequired, mustBeAdmin, async function (ctx, next) { + let events; + if (ctx.query.page && ctx.query.pagesize) { + let page = parseInt(ctx.query.page, 10); + page = page - 1; + let pagesize = parseInt(ctx.query.pagesize, 10); + events = await r.table('errors').orderBy({index: r.desc('date')}).slice(page * pagesize, page * pagesize + pagesize, {right_bound: 'open'}) + } else { + events = await r.table('errors').orderBy({index: r.desc('date')}); + } + ctx.body = events; +}) + +router.get('/api/count/exceptions', jwtrequired, mustBeAdmin, async function (ctx, next) { + const count = await r.table('errors').count(); + ctx.body = { + count: count + }; +}) + + +/**** +Organizations, only admin can create/update. Only member can view. +***/ +router.get('/api/organizations', jwtrequired, async function (ctx, next) { + if (ctx.state.user.isAdmin) { + ctx.body = await dao.getOrganizations(); + } else { + ctx.body = await [dao.getOrganization(ctx.state.user.orgid)]; + } +}) + +router.get('/api/organizations/:orgid', jwtrequired, async function (ctx, next) { + if (ctx.state.user.isAdmin) { + ctx.body = await dao.getOrganization(ctx.params.orgid); + } else if (ctx.state.user.orgid === ctx.params.orgid) { + ctx.body = await dao.getOrganization(ctx.state.user.orgid); + } else { + throw new Error('Access Denied'); + } +}) + +router.delete('/api/organizations/:orgid', jwtrequired, mustBeAdmin, async function (ctx, next) { + if (ctx.state.user.isAdmin) { + ctx.body = await dao.deleteOrganization(ctx.params.orgid); + } else { + throw new Error('Access Denied'); + } +}) + +router.post('/api/organizations', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.newOrganization(ctx.request.body); +}) + +router.put('/api/organizations/:orgid', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.updateOrganization(ctx.params.orgid, ctx.request.body); +}) + + +/**** + +Users are per org. Can be accessed by admin or their orgAdmin. + +***/ +router.get('/api/organizations/:orgid/users', jwtrequired, async function (ctx, next) { + if (ctx.state.user.isAdmin === true || ctx.state.user.isOrgAdmin === true) { + ctx.body = await dao.getUsers(ctx.params.orgid); + } else { + ctx.body = [await dao.getUserByOrgId(ctx.params.orgid, ctx.state.user.username)]; // regular users can only get themselves + } +}) + +router.get('/api/organizations/:orgid/users/:id', jwtrequired, mustBeObjectOwnerOrAdminOrOrgAdmin, async function (ctx, next) { + ctx.body = await dao.getUserByOrgId(ctx.params.orgid, ctx.params.id); +}) + +router.delete('/api/organizations/:orgid/users/:id', jwtrequired, mustBeAdminOrOrgAdmin, async function (ctx, next) { + ctx.body = await dao.deleteUser(ctx.params.id, ctx.params.orgid); +}) + +// id is the username +router.put('/api/organizations/:orgid/users/:id', jwtrequired, mustBeObjectOwnerOrAdminOrOrgAdmin, onlyAdminCanSetAdmin, async function (ctx, next) { + ctx.body = await dao.updateUserByOrgId(ctx.params.orgid, ctx.params.id, ctx.request.body); +}) + + +router.get('/api/users', jwtrequired, mustBeAdmin, async function (ctx, next) { + if (ctx.state.user.isAdmin === true || ctx.state.user.isOrgAdmin === true) { + ctx.body = await dao.getUsers(); + } else { + ctx.body = [await dao.getUserByOrgId(null, ctx.state.user.username)]; // regular users can only get themselves + } +}) + +router.get('/api/users/:id', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.getUser(ctx.params.id); +}) + +router.delete('/api/users/:id', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.deleteUser(ctx.params.id); +}) + +router.put('/api/users/:id', jwtrequired, mustBeObjectOwnerOrAdminOrOrgAdmin, onlyAdminCanSetAdmin, async function (ctx, next) { + ctx.body = await dao.saveUser(ctx.params.id, ctx.request.body); +}) + +/**** +Reports +***/ +router.get('/api/organizations/:orgid/reports/:reportid', jwtrequired, mustBeAdminOrOrgMember, async function (ctx, next) { + let tzOffset = 0; + if (ctx.query.tzOffset) { + tzOffset = Number.parseInt(ctx.query.tzOffset) + } + let vehicles; + + if (ctx.query.vehicles) { + vehicles = JSON.parse(ctx.query.vehicles); + } + + // if (ctx.query.format === 'excel') + + ctx.body = await reports.getReport(ctx.params.orgid, ctx.params.reportid, vehicles, new Date(ctx.query.startDate), new Date(ctx.query.endDate), tzOffset); +}) + +/**** +Devices +***/ +router.get('/api/organizations/:orgid/devices', jwtrequired, mustBeAdminOrOrgMember, async function (ctx, next) { + ctx.body = await dao.getDevices(ctx.params.orgid); +}) + +router.get('/api/organizations/:orgid/devices/:id', jwtrequired, mustBeAdminOrOrgMember, async function (ctx, next) { + ctx.body = await dao.getDevice(ctx.params.id, ctx.state.user.isAdmin, ctx.params.orgid); +}) + +router.delete('/api/organizations/:orgid/devices/:id', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.deleteDevice(ctx.params.id, ctx.state.user.isAdmin, ctx.params.orgid); +}) + +// No post for devices since uniquely identified by ID (IMEI) +router.put('/api/organizations/:orgid/devices/:id', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.saveDeviceByOrgID(ctx.request.body, ctx.params.id, ctx.state.user.isAdmin, ctx.params.orgid); +}) + +router.get('/api/devices', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.getDevices(); +}) + +router.get('/api/devices/:id', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.getDevice(ctx.params.id, ctx.state.user.isAdmin); +}) + +router.delete('/api/devices/:id', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.deleteDevice(ctx.params.id, ctx.state.user.isAdmin); +}) + +router.put('/api/devices/:id', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.saveDevice(ctx.request.body, ctx.params.id); +}) + +/**** +Fleets +***/ +router.get('/api/organizations/:orgid/fleets', jwtrequired, mustBeAdminOrOrgMember, async function (ctx, next) { + ctx.body = await dao.getFleets(ctx.params.orgid); +}) + +router.get('/api/organizations/:orgid/fleets/:id', jwtrequired, mustBeAdminOrOrgMember, async function (ctx, next) { + ctx.body = await dao.getFleet(ctx.params.id, ctx.state.user.isAdmin, ctx.params.orgid); +}) + +router.post('/api/organizations/:orgid/fleets', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.newFleet(ctx.request.body, ctx.params.orgid); +}) + +router.put('/api/organizations/:orgid/fleets/:id', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.updateFleet(ctx.request.body, ctx.params.id, ctx.state.user.isAdmin, ctx.params.orgid); +}) + +router.delete('/api/organizations/:orgid/fleets/:id', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.deleteFleet(ctx.params.id, ctx.state.user.isAdmin, ctx.params.orgid); +}) + +/**** + +Vehicles are per org. Can be accessed by admin or their orgAdmin or their users. + +***/ +router.get('/api/vehicles', jwtrequired, mustBeAdmin, async function (ctx, next) { + ctx.body = await dao.getVehicles(); +}) + +router.get('/api/organizations/:orgid/vehicles', jwtrequired, mustBeAdminOrOrgMember, async function (ctx, next) { + ctx.body = await dao.getVehicles(ctx.params.orgid); +}) + +router.get('/api/organizations/:orgid/vehicles/:id', jwtrequired, mustBeAdminOrOrgMember, async function (ctx, next) { + ctx.body = await dao.getVehicle(ctx.params.orgid, ctx.params.id, ctx.state.user.isAdmin); +}) + +router.delete('/api/organizations/:orgid/vehicles/:id', jwtrequired, mustBeAdminOrOrgMember, async function (ctx, next) { + ctx.body = await dao.deleteVehicle(ctx.params.orgid, ctx.params.id, ctx.state.user.isAdmin); +}) + +router.post('/api/organizations/:orgid/vehicles', jwtrequired, mustBeAdminOrOrgAdmin, async function (ctx, next) { + ctx.body = await dao.newVehicle(ctx.params.orgid, ctx.request.body); +}) + +router.put('/api/organizations/:orgid/vehicles/:id', jwtrequired, mustBeAdminOrOrgAdmin, async function (ctx, next) { + ctx.body = await dao.updateVehicle(ctx.params.orgid, ctx.params.id, ctx.request.body, ctx.state.user.isAdmin); +}) + +router.get('/api/organizations/:orgid/vehiclehistory/:id', jwtoptional, jwtcookie, mustBeAdminOrOrgMember, vehiclehistory); + +// router.post('/api/vehiclehistory/:id/geocode', jwtoptional, jwtcookie, mustBeAdmin, async function (ctx, next) { +// const id = ctx.params.id; +// const force = ctx.query.force; +// const timeout = ctx.query.timeout || null; +// const histItem = await r.table('vehiclehistory').get(id); +// const address = await reverseGeo(histItem.la, histItem.lo, timeout, force); +// histItem.ad = address; +// const retVal = await r.table('vehiclehistory').get(id).update(histItem, {returnChanges: 'always'}); +// ctx.body = retVal.changes[0].new_val; +// }) + +// last status of all vehicles for an organization +router.get('/api/organizations/:orgid/vehiclestatus', jwtoptional, jwtcookie, mustBeAdminOrOrgMember, vehiclestatus); diff --git a/src/server/lib/routes/vehiclehistory.js b/src/server/lib/routes/vehiclehistory.js new file mode 100644 index 0000000..e0692f1 --- /dev/null +++ b/src/server/lib/routes/vehiclehistory.js @@ -0,0 +1,144 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import _ from 'lodash'; +// import dao from '../dao'; +const dao = require('../dao'); +import moment from 'moment'; + +import nodeExcel from 'excel-export'; +import KilometersToMiles from "kilometers-to-miles"; +import {getStatus} from '../../../common/status'; +import {cleanData, getAccuracy, nullToBlank, onlyVisibleHistory, addStartStop, rollup, ignitionMileage, startStopMileage} from '../../../common/helpers'; +import todir from '../../../common/todir'; +import tomiles from '../../../common/tomiles'; +import reports from '../reports'; +import {street, city, state} from '../../../common/addressdisplay'; +import milesfield from '../../../common/milesfield'; + +export default async (ctx, next) => { + const showLatLong = ctx.query.latlong === 'true'; + const tzOffset = ctx.query.tzOffset ? Number.parseInt(ctx.query.tzOffset) : 0; + const verbose = ctx.query.verbose === 'true'; + + const rollupStationaryEvents = ctx.query.rollupStationaryEvents === 'true'; + const calculateDistanceBetween = ctx.query.calculateDistanceBetween; + const startDate = new Date (ctx.query.startDate); + const endDate = new Date(ctx.query.endDate); + const reverse = ctx.query.reverse === 'true' + + let history = await dao.getVehicleHistory(ctx.params.orgid, ctx.params.id, startDate, endDate); + + if (ctx.query.format === 'excel') { + if (!verbose) { + history = onlyVisibleHistory(history); + } + history = cleanData(history); + history = addStartStop(history); + + if (rollupStationaryEvents) { + history = rollup(history); + } + + if (calculateDistanceBetween === 'ignition') { + history = ignitionMileage(history); + } else { + history = startStopMileage(history); + } + + if (reverse) { + history = history.reverse(); + } + + let conf = {}; + // conf.stylesXmlFile = "styles.xml"; + conf.cols = [ + { + caption: 'UTC time', + type: 'string', + width: 25, + beforeCellWrite: function() { + return function(row, cellData, eOpt) { + return (new Date(cellData)).toISOString(); + } + }() + }, + { + caption: 'Local Time (' + tzOffset + ' minutes offset from UTC)', + type: 'date', + width: 20, + beforeCellWrite: function() { + let originDate = new Date(Date.UTC(1899, 11, 30)); + return function(row, cellData, eOpt) { + return ((cellData - originDate) + (tzOffset * 60 * 1000)) / (24 * 60 * 60 * 1000); + } + }() + }, + // individual vehicle history + {caption:'Address', type:'string', width:35}, + {caption:'City', type:'string', width:25}, + {caption:'State', type:'string', width:15}, + {caption:'Miles', type:'string', width:20}]; + + if (verbose) { + conf.cols.push({caption:'Odometer', type:'number', width:15}) + conf.cols.push({caption:'Hour Meter', type:'string', width:20}); + } + conf.cols.push({caption:'Dir', type:'string', width:5}) + conf.cols.push({caption:'Speed', type:'number', width:10}) + + if (showLatLong) { + conf.cols.push({caption:'Lat', type:'number', width:10}); + conf.cols.push({caption:'Long', type:'number', width:10}); + } + + conf.cols.push({caption:'Status', type:'string', width:20}); + + if (verbose) { + conf.cols.push({caption:'Online', type:'string', width:5}) + conf.cols.push({caption:'Battery', type:'number', width:5}) + } + + conf.cols.push({caption:'GPS', type:'string', width:8}); + + conf.rows = history.map(function (item) { + const arr = [ + nullToBlank(item.d), + nullToBlank(item.d), + nullToBlank(street(item)), + nullToBlank(city(item)), + nullToBlank(state(item)), + nullToBlank(milesfield(item))] + + if (verbose) { + arr.push(nullToBlank(tomiles(item.m))); + arr.push(nullToBlank(item.h)); + } + + arr.push(nullToBlank(todir(item))); + arr.push(nullToBlank(tomiles(item.s))); + + if (showLatLong) { + arr.push(nullToBlank(item.la)); + arr.push(nullToBlank(item.lo)); + } + + arr.push(nullToBlank(getStatus(item))); + + if (verbose) { + arr.push(nullToBlank(item.b ? 'Buffered' : 'Yes')) + arr.push(nullToBlank(item.bp)); + } + + arr.push(nullToBlank(getAccuracy(item.g))); + + return arr; + }); + + const result = nodeExcel.execute(conf); + ctx.body = new Buffer(result, 'binary'); + ctx.set('Content-Type', 'application/vnd.openxmlformats'); + ctx.set("Content-Disposition", "attachment; filename=" + "VehicleHistoryReport" + moment().format('YYYY-M-DD-HH-MM-SS') + ".xlsx"); + } else { + ctx.body = history; + } +} diff --git a/src/server/lib/routes/vehiclestatus.js b/src/server/lib/routes/vehiclestatus.js new file mode 100644 index 0000000..5dcc5cd --- /dev/null +++ b/src/server/lib/routes/vehiclestatus.js @@ -0,0 +1,123 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import _ from 'lodash'; +// import dao from '../dao'; +const dao = require('../dao'); +import moment from 'moment'; + +import nodeExcel from 'excel-export'; +import KilometersToMiles from "kilometers-to-miles"; +import {getStatus} from '../../../common/status'; +import {cleanData, getAccuracy, nullToBlank} from '../../../common/helpers'; +import todir from '../../../common/todir'; +import tomiles from '../../../common/tomiles'; +import reports from '../reports'; +import {street, city, state} from '../../../common/addressdisplay'; +import milesfield from '../../../common/milesfield'; + +export default async (ctx, next) => { + const showLatLong = ctx.query.latlong === 'true'; + const tzOffset = ctx.query.tzOffset ? Number.parseInt(ctx.query.tzOffset) : 0; + const verbose = ctx.query.verbose === 'true'; + let status = _.flattenDeep(await dao.getVehicles(ctx.params.orgid)); + + if (ctx.query.format === 'excel') { + status = cleanData(status); + const conf = {}; + // conf.stylesXmlFile = "styles.xml"; + conf.cols = [ + {caption:'Name', type:'string', width:40}, + { + caption: 'UTC', + type: 'string', + width: 25, + beforeCellWrite: function() { + return function(row, cellData, eOpt) { + try { + return (new Date(cellData)).toISOString(); + } catch (e) { + return e.stack; + } + } + }() + }, + { + caption: 'Local Time (' + tzOffset + ' minutes offset)', + type:'date', width:20, beforeCellWrite: function() { + const originDate = new Date(Date.UTC(1899, 11, 30)); + return function(row, cellData, eOpt) { + return ((cellData - originDate) + (tzOffset * 60 * 1000)) / (24 * 60 * 60 * 1000); + } + }()}, + // fleet history + {caption:'Address', type:'string', width:35}, + {caption:'City', type:'string', width:25}, + {caption:'State', type:'string', width:15}] + + if (verbose) { + conf.cols.push({caption:'Odometer', type:'number', width:20}); + conf.cols.push({caption:'Hour Meter', type:'string', width:20}); + } + + conf.cols.push({caption:'Dir', type:'string', width:5}) + conf.cols.push({caption:'Speed', type:'number', width:10}); + + if (showLatLong) { + conf.cols.push({caption:'Lat', type:'number', width:10}); + conf.cols.push({caption:'Long', type:'number', width:10}); + } + + conf.cols.push({caption:'Status', type:'string', width:20}); + + if (verbose) { + conf.cols.push({caption:'Online', type:'string', width:5}); + conf.cols.push({caption:'Battery', type:'number', width:5}); + } + conf.cols.push({caption:'GPS', type:'string', width:8}); + + conf.rows = status.map(function (item) { + if (!item.last) { + item.last = {} + } + let arr = [ + nullToBlank(item.name), + nullToBlank(item.last.d), + nullToBlank(item.last.d), + nullToBlank(street(item.last)), + nullToBlank(city(item.last)), + nullToBlank(state(item.last))]; + + if (verbose) { + arr.push(nullToBlank(tomiles(item.last.m))); + arr.push(nullToBlank(item.last.h)); + } + + arr.push(nullToBlank(todir(item.last))); + + arr.push(nullToBlank(tomiles(item.last.s))); + + if (showLatLong) { + arr.push(nullToBlank(item.last.la)); + arr.push(nullToBlank(item.last.lo)); + } + + arr.push(nullToBlank(getStatus(item.last))); + + if (verbose) { + arr.push(nullToBlank(item.last.b ? 'Buffered' : 'Yes')) + arr.push(nullToBlank(item.last.bp)); + } + + arr.push(nullToBlank(getAccuracy(item.last.g))); + + return arr; + }); + + const result = nodeExcel.execute(conf); + ctx.body = new Buffer(result, 'binary'); + ctx.set('Content-Type', 'application/vnd.openxmlformats'); + ctx.set("Content-Disposition", "attachment; filename=" + "ActivityReport" + moment().format('YYYY-M-DD-HH-MM-SS') + ".xlsx"); + } else { + ctx.body = status; + } +} diff --git a/src/server/lib/security.js b/src/server/lib/security.js new file mode 100644 index 0000000..31dd4ba --- /dev/null +++ b/src/server/lib/security.js @@ -0,0 +1,79 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import Promise from 'bluebird'; +import {getUser} from './dao'; +import {get} from 'lodash'; +const adapt = require('koa-adapter-bluebird'); // uses bluebird-co for performance + +export async function mustBeAdmin (ctx, next) { + if (ctx.state.user.isAdmin !== true) { + ctx.status = 403; + ctx.body = { success: 'false', message: 'Must be admin'}; + } else { + await next(); + } +} + +export async function mustBeAdminOrOrgAdmin (ctx, next) { + if ( get(ctx, 'state.user.isAdmin') === true || + ( get(ctx, 'state.user.isOrgAdmin') === true && get(ctx, 'state.user.orgid') === get(ctx, 'params.orgid'))) { + await next(); + } else { + ctx.status = 403; + ctx.body = { success: 'false', message: 'Access denied'}; + } +} + +export async function mustBeObjectOwnerOrAdminOrOrgAdmin (ctx, next) { + function fail() { + ctx.status = 403; + ctx.body = { success: 'false', message: 'Access denied'}; + return; + } + + if ( get(ctx, 'state.user.isAdmin') === true || + (get(ctx, 'state.user.isOrgAdmin') === true && get(ctx, 'state.user.orgid') === get(ctx, 'request.body.orgid'))) { + return next(); + } else { + let url = ctx.request.path.split('/'); + // e.g., ["", "api", "organizations", "default", "users"] + + let objType = url[4]; + + if (url[4] === 'users' || url[2] === 'users') { + let username = ctx.state.user.username; + let obj = await getUser(ctx.params.id); + + if (username === obj.username) { + await next(); + } else { + fail(); + } + } else { + fail(); + } + } +} + +export async function onlyAdminCanSetAdmin (ctx, next) { + if (get(ctx, 'state.user.isAdmin') === true) { + await next(); + } else if (get(ctx, 'state.user.isOrgAdmin') === true) { + delete ctx.request.body.isAdmin; + await next(); + } else { + delete ctx.request.body.isAdmin; + delete ctx.request.body.isOrgAdmin; + await next(); + } +} + +export async function mustBeAdminOrOrgMember (ctx, next) { + if (get(ctx, 'state.user.isAdmin') === true + || get(ctx, 'state.user.orgid') === get(ctx, 'params.orgid')) { + await next(); + } else { + ctx.status = 403; + ctx.body = { success: 'false', message: 'Access denied'}; + } +} diff --git a/src/server/lib/sockets.js b/src/server/lib/sockets.js new file mode 100644 index 0000000..0c52a05 --- /dev/null +++ b/src/server/lib/sockets.js @@ -0,0 +1,100 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +// holds socketio objects since we have one for http and https +import Promise from 'bluebird'; +import _ from 'lodash'; +import r from '../../common/db'; +import {jwtSecret} from '../../../config/web.js'; +import JWT from 'jsonwebtoken'; Promise.promisifyAll(JWT); +import {getVehicles} from './dao'; +import {EventEmitter} from 'events'; + +const ee = new EventEmitter(); +ee.setMaxListeners(Infinity); +const ios = []; +const opts = {}; + +function cookiestring2object(str) { + let result = {}; + if (str != null) { + str = str.split('; '); + for (let i = 0; i < str.length; i++) { + let cur = str[i].split('='); + result[cur[0]] = cur[1]; + } + } + return result; +} + +const tables = ['vehiclehistory', 'users', 'organizations', 'devices', 'vehicles', 'errors', 'fleets']; + +(async function() { + for (let table of tables) { + const cursor = await r.table(table).changes(); + cursor.each(function (nothing, changes) { + if (changes != null) { + ee.emit(table, changes); + } + }) + } +})(); + +module.exports.register = function (io) { + ios.push(io); + io.on('connection', async function (socket) { + const cookies = cookiestring2object(socket.handshake.headers.cookie); + const token = cookies.jwt; + + let user; + try { + user = await JWT.verifyAsync(token, jwtSecret, opts); + } catch (e) { + // ignore random connections or invalid JWTs + console.error(e); + return; + } + const vehicleOrgs = {}; + + if (user.isAdmin !== true) { + const allVehicles = await getVehicles(user.orgid); + allVehicles.forEach(function (item) { + vehicleOrgs[item.id] = item.orgid; + }) + } + + const listeners = {}; + for (let table of tables) { + const onchange = async function (changes) { + if (user.isAdmin === true) { + socket.emit(table, JSON.stringify(changes)); + } else { + let obj; + let idKey; + if (table === 'devices') { + idKey = 'imei'; + } else { + idKey = 'id'; + } + + if (changes.old_val != null) { + obj = _.get(changes, ['old_val'], idKey); + } else { + obj = _.get(changes, ['new_val'], idKey); + } + + if (obj && obj.orgid === user.orgid) { + socket.emit(table, JSON.stringify(changes)); + } + } + } + ee.on(table, onchange); + listeners[table] = onchange; + } + + socket.on('disconnect', function () { + Object.keys(listeners).forEach(function (key) { + ee.removeListener(key, listeners[key]); + }); + }) + }); +} diff --git a/src/server/runner.js b/src/server/runner.js new file mode 100644 index 0000000..c18fdb9 --- /dev/null +++ b/src/server/runner.js @@ -0,0 +1,17 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +// Run this to auto-reload the server on file changes. +const nodemon = require('nodemon'); + +nodemon({ + script: 'server.js', + ext: 'js json', + "execMap": { + "js": "babel-node" + }, + "ignore": [ + ".git", + "client/**", + "**/*.spec.js" + ] +}); diff --git a/src/server/server.js b/src/server/server.js new file mode 100644 index 0000000..df68aab --- /dev/null +++ b/src/server/server.js @@ -0,0 +1,106 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import Promise from 'bluebird'; +Promise.config({ + longStackTraces: config.longStackTraces +}); +global.Promise = Promise; +import bunyan from 'bunyan'; +import config from '../../config/web.js'; +import cluster from 'cluster'; +import fs from 'fs'; +import net from 'net'; +import app from './lib/app'; +import http from 'http'; +import spdy from 'spdy'; +import sticky from 'socketio-sticky-session'; +import sockets from './lib/sockets'; + +const port = config.port; +const log = bunyan.createLogger({ + name: 'server', + // level: 'debug' +}); + +log.info('Starting server'); + +process.on('exit', function () { + log.info('Cluster master? ' + cluster.isMaster + ' Process exit at ' + (new Date).toISOString()); +}); + + +let credentials; + +if (config.spdy || config.https) { + credentials = { + key: fs.readFileSync('../../config/privkey.pem', 'utf8'), + cert: fs.readFileSync('../../config/cert.pem', 'utf8') + }; + if (!credentials) { + log.error("SSL certs need to be installed for SPDY/HTTPS"); + process.exit(1); + } +} + +function getHttpServer() { + let server = require('http').createServer(require('./lib/app').callback()); + sockets.register(require('socket.io').listen(server)); + return server; +} + +function getTlsServer() { + let server; + if (config.spdy) { + log.info('SPDY enabled'); + server = require('spdy').createServer(credentials, require('./lib/app').callback()); + } else if (config.https) { + log.info('HTTPS enabled'); + server = require('https').createServer(credentials, require('./lib/app').callback()); + } + sockets.register(require('socket.io').listen(server)); + return server; +} + +const httpServer = getHttpServer(); +const tlsServer = getTlsServer(); + +if (config.cluster) { + let options = { + ignoreMissingHeader: true + }; + + if (config.isReverseProxied) { + options.proxy = true; //activate layer 4 patching + options.header = 'x-forwarded-for'; //provide here your header containing the users ip + } + + if (httpServer) + httpServer = sticky(options, httpServer); + + if (tlsServer) + tlsServer = sticky(options, httpServer); +} + +if (httpServer) { + httpServer.listen(config.port, function () { + log.info('Sticky cluster worker ' + (cluster.worker ? cluster.worker.id : '') + ' server listening on port ' + config.port); + }); +} + +if (tlsServer) { + tlsServer.listen(config.tlsport, function () { + log.info('TLS Sticky cluster worker ' + (cluster.worker ? cluster.worker.id : '') + ' server listening on port ' + config.tlsport); + }); +} + + +if (process.getuid() === 0) { // if we are root + // we have opened the sockets, now drop our root privileges + process.setgid('nobody'); + process.setuid('nobody'); + // Newer node versions allow you to set the effective uid/gid + if (process.setegid) { + process.setegid('nobody'); + process.seteuid('nobody'); + } +} diff --git a/src/test/datehelpertest.js b/src/test/datehelpertest.js new file mode 100755 index 0000000..28c96d3 --- /dev/null +++ b/src/test/datehelpertest.js @@ -0,0 +1,64 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import _ from 'lodash'; +import {toDate} from '../helper/datehelper'; + +test('August date', function (t) { + t.plan(2); // Tell tape how many assertions we plan to test. + // This is needed in case some tests are asynchronous, so tape knows when to be done. + + const date = toDate('20150819141220'); + t.ok(_.isDate(date)); // assert that the result is in fact a Date. + t.equal(date.toUTCString(), 'Wed, 19 Aug 2015 14:12:20 GMT') +}); + +test('January date', function (t) { + t.plan(2); // Tell tape how many assertions we plan to test. + // This is needed in case some tests are asynchronous, so tape knows when to be done. + + const date = toDate('20150119141220'); + t.ok(_.isDate(date)); // assert that the result is in fact a Date. + t.equal(date.toUTCString(), 'Mon, 19 Jan 2015 14:12:20 GMT'); +}); + +test('0 month date should throw', function (t) { + t.plan(1); // Tell tape how many assertions we plan to test. + // This is needed in case some tests are asynchronous, so tape knows when to be done. + t.throws(function () { + toDate('20150019141220'); + }, TypeError) +}); + +test('December date', function(t){ + t.plan(2); + + const date = toDate('20151219141220'); + t.ok('Dec Test',_.isDate(date)); + t.equal(date.toUTCString(), 'Sat, 19 Dec 2015 14:12:20 GMT'); + +}); + +test('Missing last digit date should throw', function (t) { + t.plan(1); + t.throws(function () { + toDate('2015081914122') // missing last digit + }, TypeError, 'Invalid date string') +}); + +test('a live date', function(t){ + t.plan(2); + + const date = toDate('20150804183415'); + t.ok('Dec Test',_.isDate(date)); + t.equal(date.toUTCString(), 'Tue, 04 Aug 2015 18:34:15 GMT'); + +}); + +test('problematic date', function (t) { + t.plan(2); + const date = toDate('20150804024111'); + + t.ok('Dec Test',_.isDate(date)); + t.equal(date.toUTCString(), 'Tue, 04 Aug 2015 02:41:11 GMT'); +}) diff --git a/src/test/decimaltohextest.js b/src/test/decimaltohextest.js new file mode 100644 index 0000000..f16583c --- /dev/null +++ b/src/test/decimaltohextest.js @@ -0,0 +1,11 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import decimalToHex from '../listen/decimaltohex'; + +test('test', function (t) { + t.plan(1); + + const hex = decimalToHex(108); + t.equal(hex, '6C'); +}) diff --git a/src/test/eventreportparsertest.js b/src/test/eventreportparsertest.js new file mode 100755 index 0000000..9017b2c --- /dev/null +++ b/src/test/eventreportparsertest.js @@ -0,0 +1,248 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import parse from '../helper/eventreportparser'; +import decimalToHex from '../listen/decimaltohex'; + +// https://lodash.com/docs +const _ = require('lodash') + +test('parse GTPNA', function (t) { + t.plan(4); // Tell tape how many assertions we plan to test. + // This is needed in case some tests are asynchronous, so tape knows when to be done. + const x = '+RESP:GTPNA,060100,135790246811220,,20090214093254,11F0$' + + const parsed = parse(x); + + t.equal(parsed.type, 'RESP:GT'); + t.equal(parsed.cmd, 'PNA'); + t.equal(parsed.args.length, 5); + t.equal(parsed.shorttype, 'RESP'); +}); + + +test('parse Buffered GTPNA', function (t) { + // gv300 + t.plan(4); // Tell tape how many assertions we plan to test. + // This is needed in case some tests are asynchronous, so tape knows when to be done. + const x = '+BUFF:GTPNA,060100,135790246811220,,20090214093254,11F0$' + + const parsed = parse(x); + + t.equal(parsed.type, 'BUFF:GT'); + t.equal(parsed.cmd, 'PNA'); + t.equal(parsed.args.length, 5); + t.equal(parsed.shorttype, 'BUFF'); +}); + + +test('parse +RESP:GTPDP,360100,864251020143040,,,20160318001408,0020$', function (t) { + // gv500 ! + t.plan(1); // Tell tape how many assertions we plan to test. + // This is needed in case some tests are asynchronous, so tape knows when to be done. + const x = '+RESP:GTPDP,360100,864251020143040,,,20160318001408,0020$' + const parsed = parse(x); + t.equal(decimalToHex(parsed.count, 4), '0020'); +}) + +test('parse GV500 MPN', function (t) { + // gv500 ! + t.plan(3); // Tell tape how many assertions we plan to test. + // This is needed in case some tests are asynchronous, so tape knows when to be done. + const x = '+BUFF:GTMPN,360100,864251020143040,,,0,,,,,,,0000,0000,0000,0000,00,20160318002638,001E$' + const parsed = parse(x); + t.equal(parsed.imei, '864251020143040'); + t.equal(decimalToHex(parsed.count, 4), '001E'); + t.equal(parsed.shorttype, 'BUFF'); +}) + +test('parse GV500 STT', function (t) { + const x = '+RESP:GTSTT,360100,864251020143040,,,42,0,,,,,,,0310,0260,74AF,AC5A,00,20160318002641,001F$'; + t.plan(2); + const parsed = parse(x); + t.equal(decimalToHex(parsed.count, 4), '001F'); + t.equal(parsed.vin, ''); + +}) + +test('parse GV500 OPN', function (t) { + const x = '+RESP:GTOPN,360100,864251020143040,,,0,,,,,,,0310,0260,74AF,AC5A,00,20160318002642,0020$'; + t.plan(2); + const parsed = parse(x); + t.equal(decimalToHex(parsed.count, 4), '0020'); + t.equal(parsed.vin, ''); +}) + +test('parse buffered GV500 OPN', function (t) { + const x = '+BUFF:GTOPN,360100,864251020143040,,,0,,,,,,,0310,0260,74AF,AC5A,00,20160318002642,0020$'; + t.plan(2); + const parsed = parse(x); + t.equal(decimalToHex(parsed.count, 4), '0020'); + t.equal(parsed.vin, ''); +}) + +test('parse GV500 RTL', function (t) { + const x = '+RESP:GTRTL,360100,864251020143040,,,,00,1,1,1.0,0,296.8,-93.296121,44.901623,20160318002705,0310,0260,74AF,AC5A,00,0.0,20160318002706,0021$'; + t.plan(2); + const parsed = parse(x); + t.equal(decimalToHex(parsed.count, 4), '0021'); + t.equal(parsed.vin, ''); +}) + +test('parse buffered STT', function (t) { + const x = '+BUFF:GTSTT,360100,864251020143040,,,42,0,,,,,,,0310,0260,74AF,AC5A,00,20160318002641,001F$'; + t.plan(2); + const parsed = parse(x); + t.equal(decimalToHex(parsed.count, 4), '001F'); + t.equal(parsed.vin, ''); +}) + +test('parse PDP', function (t) { + const x = '+RESP:GTPDP,360100,864251020143040,,,20160318012452,0041$'; + t.plan(2); + const parsed = parse(x); + t.equal(decimalToHex(parsed.count, 4), '0041'); + t.equal(parsed.vin, ''); +}) + +test('parse IGL', function (t) { + const x = '+RESP:GTIGL,360100,864251020143040,,,,00,1,1,0.0,0,270.2,-93.296109,44.901704,20160318013354,0310,0260,74AF,AC5A,00,0.0,20160318013355,004D$'; + t.plan(6); + const parsed = parse(x); + t.equal(parsed.imei, '864251020143040'); + t.equal(parsed.longitude, -93.296109); + t.equal(parsed.latitude, 44.901704); + t.equal(parsed.altitude, 270.2); + t.equal(decimalToHex(parsed.count, 4), '004D'); + t.equal(parsed.vin, ''); + // t.equal(parsed.senddate, new Date('Thu Mar 17 2016 20:33:55 GMT-0500 (CDT)')); +}) + +test('parse OPN', function (t) { + const x = '+RESP:GTOPN,360100,864251020143040,,,0,,,,,,,0310,0260,74AF,AC5A,00,20160318013256,0045$'; + t.plan(3); + const parsed = parse(x); + t.equal(parsed.imei, '864251020143040'); + t.equal(decimalToHex(parsed.count, 4), '0045'); + t.equal(parsed.vin, ''); + // t.equal(parsed.senddate, new Date('Thu Mar 17 2016 20:33:55 GMT-0500 (CDT)')); +}) + + + +test('parse CFG', function (t) { + const x = '+ACK:GTCFG,360100,864251020143040,gv500,0000,20160318041337,005B$'; + t.plan(2); + const parsed = parse(x); + t.equal(parsed.imei, '864251020143040'); + t.equal(decimalToHex(parsed.count, 4), '005B'); +}) + +test('parse INF', function (t) { + const x = '+BUFF:GTINF,360100,864251020143040,,gv500,42,8901260761283398892f,20,0,1,12264,,3.87,0,1,,,20160318041335,,,,,,+0000,0,20160318041337,005C$'; + const parsed = parse(x); + t.plan(1); + t.equal(decimalToHex(parsed.count, 4), '005C'); + + // todo +}) + +test('parse GSM', function (t) { + const x = '+BUFF:GTGSM,360100,864251020143040,,RTL,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0310,0260,74af,ac5a,22,00,20160318042520,006C$'; + const parsed = parse(x); + t.plan(1); + t.equal(decimalToHex(parsed.count, 4), '006C'); + // todo +}) + +test('parse ', function (t) { + const x = '+ACK:GTFRI,360100,864251020143040,gv500,0000,20160318151632,0161$'; + const parsed = parse(x); + t.plan(1); + t.equal(decimalToHex(parsed.count, 4), '0161'); + // todo +}) + +test('parse buffered FRI', function (t) { + const x = '+BUFF:GTFRI,250506,863286020988292,,,10,1,0,0.0,27,,30.543643,50.422092,20160317205427,,,,,,16138.4,01265:18:43,,,9,110000,,,,20160318044421,AB27$'; + const parsed = parse(x); + t.plan(18); + t.equal(decimalToHex(parsed.count, 4), 'AB27'); + t.equal(parsed.imei, '863286020988292'); + t.equal(parsed.senddate.toISOString(), '2016-03-18T04:44:21.000Z'); + t.equal(parsed.gpsdate.toISOString(), '2016-03-17T20:54:27.000Z'); + t.equal(parsed.version, '250506'); + t.equal(parsed.rid, '1'); + t.equal(parsed.rty, '0'); + t.equal(parsed.number, '1'); + t.equal(parsed.accuracy, 0); + t.equal(parsed.speed, 0); + t.equal(parsed.azimuth, 27); + t.equal(_.isNaN(parsed.altitude), true); + t.equal(decimalToHex(parsed.count, 4), 'AB27'); + t.equal(parsed.hourmeter, '01265:18:43'); + t.equal(parsed.batteryPercent, 9); + t.equal(parsed.status, '110000'); + t.equal(parsed.friendlyStatus, 'ignition off rest'); + t.equal(parsed.mileage, 16138.4); +}) + +test('parse heartbeat ack', function (t) { + const x = '+ACK:GTHBD,360100,864251020143040,gv500,20160319023819,0172$'; + const parsed = parse(x); + t.plan(4); + t.equal(decimalToHex(parsed.count, 4), '0172'); + t.equal(parsed.imei, '864251020143040'); + t.equal(parsed.name, 'gv500'); + t.equal(parsed.vin, undefined); +}) + +test('parse BSI ack', function (t) { + const x = '+ACK:GTBSI,360100,864251020143040,gv500,0000,20160319172911,018C$'; + const parsed = parse(x); + t.plan(2); + t.equal(decimalToHex(parsed.count, 4), '018C'); + t.equal(parsed.imei, '864251020143040') +}) + +test('parse TOW ack gv500', function (t) { + const x = '+ACK:GTTOW,360100,864251020143040,gv500,0000,20160320035131,01BE$'; + const parsed = parse(x); + t.plan(2); + t.equal(decimalToHex(parsed.count, 4), '01BE'); + t.equal(parsed.imei, '864251020143040') +}) + +test('parse VER', function (t) { + const x = '+RESP:GTVER,360201,864251020143727,,gv500,GV500,0209,0101,20160329161513,061B$'; + const parsed = parse(x); + t.plan(2); + t.equal(decimalToHex(parsed.count, 4), '061B'); + t.equal(parsed.imei, '864251020143727') +}) + +test('parse RTO', function (t) { + const x = '+ACK:GTRTO,360201,864251020143727,gv500,VER,FFFF,20160329161513,061A$'; + const parsed = parse(x); + t.plan(2); + t.equal(decimalToHex(parsed.count, 4), '061A'); + t.equal(parsed.imei, '864251020143727') +}) + +test('TOW config', function (t) { + const x = '+ACK:GTTOW,360303,864251020143636,gv500,FFFF,20160707194905,00B2$'; + const parsed = parse(x); + t.plan(3); + t.equal(decimalToHex(parsed.count, 4), '00B2'); + t.equal(parsed.imei, '864251020143636') + t.equal(parsed.shorttype, 'ACK') +}) + +test('DTT message', function (t) { + const x = '+RESP:GTDTT,250403,863286020190428,,,,0,8,1235UUU,0,0.0,55,,37.534451,48.632817,20160828135149,,,,,,,,,,20160828143537,006A$'; + const parsed = parse(x); + t.plan(3); + t.equal(decimalToHex(parsed.count, 4), '006A'); + t.equal(parsed.imei, '863286020190428') + t.equal(parsed.shorttype, 'RESP') +}) diff --git a/src/test/helperstest.js b/src/test/helperstest.js new file mode 100644 index 0000000..bae7a36 --- /dev/null +++ b/src/test/helperstest.js @@ -0,0 +1,169 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import {isMotion} from '../common/helpers'; + +test('towing is not considered motion', function(t) { + t.plan(1); + + t.equal(isMotion({ + "buffered": false, + "type": "RESP:GT", + "cmd": "TOW", + "friendly": "Towing", + "version": "250404", + "imei": "863286020049095", + "name": "", + "rid": "0", + "rty": "0", + "number": "1", + "accuracy": 1, + "speed": 0.2, + "azimuth": 85, + "altitude": null, + "gpsdate": "2015-12-27T00:22:25.000Z", + "mcc": "", + "mnc": "", + "lac": "", + "cellid": "", + "mileage": 1605.6, + "senddate": "2015-12-27T00:22:25.000Z", + "count": 8885 + }), false); +}); + + +test('harsh behavior is motion', function(t) { + t.plan(1); + + t.equal(isMotion({ + "buffered": false, + "type": "RESP:GT", + "cmd": "HBM", + "friendly": "Harsh acceleration or braking", + "version": "250404", + "imei": "863286020049095", + "name": "", + "rid": "1", + "rty": "1", + "number": "1", + "accuracy": 1, + "speed": 41.1, + "azimuth": 185, + "altitude": null, + "gpsdate": "2015-12-26T18:44:21.000Z", + "mcc": "", + "mnc": "", + "lac": "", + "cellid": "", + "mileage": 1601, + "senddate": "2015-12-26T18:44:21.000Z", + "count": 8850 + }), true); +}) + +test('ignition on is not motion', function(t) { + t.plan(1); + + t.equal(isMotion({ + "buffered": false, + "type": "RESP:GT", + "cmd": "IGN", + "friendly": "Ignition on", + "version": "250404", + "imei": "863286020049095", + "name": "", + "ignitionDuration": 3271, + "accuracy": 0, + "speed": 0, + "azimuth": 83, + "altitude": null, + "gpsdate": "2015-12-26T17:21:09.000Z", + "mcc": "", + "mnc": "", + "lac": "", + "cellid": "", + "hourmeter": "00037:35:34", + "mileage": 1600.4, + "senddate": "2015-12-26T18:15:38.000Z", + "count": 8841 + }), false); +}) + + +test('ignition off rest is not motion', function(t) { + t.plan(1); + + t.equal(isMotion({ + "buffered": true, + "type": "BUFF:GT", + "cmd": "FRI", + "friendly": "Fixed report", + "version": "250404", + "imei": "863286020049095", + "name": "", + "powervcc": "", + "rid": "1", + "rty": "0", + "number": "1", + "accuracy": 1, + "speed": 0, + "azimuth": 83, + "altitude": null, + "longitude": -93, + "latitude": 44, + "gpsdate": "2015-12-26T16:53:05.000Z", + "mcc": "", + "mnc": "", + "lac": "", + "cellid": "", + "mileage": 1600.4, + "hourmeter": "00037:35:14", + "ain1": "", + "ain2": "", + "batteryPercent": 48, + "status": "110000", + "senddate": "2015-12-26T16:56:16.000Z", + "count": 8820, + "friendlyStatus": "ignition off rest" + }), false); +}) + + +test('idling is not motion', function(t) { + t.plan(1); + + t.equal(isMotion({ + "buffered": false, + "type": "RESP:GT", + "cmd": "FRI", + "friendly": "Fixed report", + "version": "250404", + "imei": "863286020049095", + "name": "", + "powervcc": "", + "rid": "1", + "rty": "0", + "number": "1", + "accuracy": 1, + "speed": 0, + "azimuth": 188, + "altitude": null, + "longitude": -93, + "latitude": 44, + "gpsdate": "2015-12-26T18:49:57.000Z", + "mcc": "", + "mnc": "", + "lac": "", + "cellid": "", + "mileage": 1603.1, + "hourmeter": "00037:45:44", + "ain1": "", + "ain2": "", + "batteryPercent": 99, + "status": "220100", + "senddate": "2015-12-26T18:50:00.000Z", + "count": 8854, + "friendlyStatus": "ignition on motion" + }), false); +}) diff --git a/src/test/jeseventparsertest.js b/src/test/jeseventparsertest.js new file mode 100644 index 0000000..d05ca1c --- /dev/null +++ b/src/test/jeseventparsertest.js @@ -0,0 +1,53 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import _ from 'lodash'; +import parse from '../helper/eventreportparser'; +import decimalToHex from '../listen/decimaltohex'; + +// test('JES (engine status)', function (t) { +// const x = '+RESP:GTJES,360303,864251020142968,,gv500,70007F,,1810,1172,27,20,74,41,0,0.0,117,128.4,37.578034,48.719447,20160818170736,,,,,,103.0,20160818170737,00DD$'; +// const parsed = parse(x); +// t.plan(29); +// t.equal(parsed.imei, '864251020142968', 'imei') +// t.equal(parsed.name, 'gv500', 'name'); +// t.equal(parsed.reportMask, parseInt('70007F', 16), 'report mask'); +// t.equal(parsed.journeyConsumption, , 'journeyConsumption'); +// t.equal(parsed.maxRPM, 1810, 'maxRPM'); +// t.equal(parsed.averageRPM, 1172, 'averageRPM'); +// t.equal(parsed.maxThrottlePosition, 27, 'maxThrottlePosition'); +// t.equal(parsed.averageThrottlePosition, 20, 'averageThrottlePosition'); +// t.equal(parsed.maxEngineLoad, 74, 'maxEngineLoad'); +// t.equal(parsed.averageEngineLoad, 41, 'averageEngineLoad'); +// t.equal(parsed.accuracy, 0, 'accuracy'); +// t.equal(parsed.speed, 0.0, 'speed'); +// t.equal(parsed.azimuth, 117, 'azimuth'); +// t.equal(parsed.altitude, 128.4, 'altitude'); +// t.equal(parsed.longitude, 37.578034); +// t.equal(parsed.latitude, 48.719447); +// t.equal(decimalToHex(parsed.count, 4), '00DD', 'count'); +// }) + +// +// test('Another JES (engine status)', function (t) { +// const x = '+RESP:GTJES,360303,864251020143636,,gv500,70007F,,7942,4978,0,0,55,26,0,0.0,74,119.1,32.723300,50.514457,20160817162026,,,,,,103.1,20160817162027,0951$'; +// const parsed = parse(x); +// t.plan(29); +// t.equal(parsed.imei, '864251020142968', 'imei') +// t.equal(parsed.name, 'gv500', 'name'); +// t.equal(parsed.reportMask, parseInt('70007F', 16), 'report mask'); +// t.equal(parsed.journeyConsumption, , 'journeyConsumption'); +// t.equal(parsed.maxRPM, 7942, 'maxRPM'); +// t.equal(parsed.averageRPM, 4978, 'averageRPM'); +// t.equal(parsed.maxThrottlePosition, 00, 'maxThrottlePosition'); +// t.equal(parsed.averageThrottlePosition, 0, 'averageThrottlePosition'); +// t.equal(parsed.maxEngineLoad, 55, 'maxEngineLoad'); +// t.equal(parsed.averageEngineLoad, 26, 'averageEngineLoad'); +// t.equal(parsed.accuracy, 0, 'accuracy'); +// t.equal(parsed.speed, 0.0, 'speed'); +// t.equal(parsed.azimuth, 74, 'azimuth'); +// t.equal(parsed.altitude, 119.1, 'altitude'); +// t.equal(parsed.longitude, 32.723300); +// t.equal(parsed.latitude, 50.514457); +// t.equal(decimalToHex(parsed.count, 4), '0951', 'count'); +// }) diff --git a/src/test/jestest.js b/src/test/jestest.js new file mode 100644 index 0000000..6e16247 --- /dev/null +++ b/src/test/jestest.js @@ -0,0 +1,55 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import _ from 'lodash'; +import parse from '../helper/eventreportparser'; +import decimalToHex from '../listen/decimaltohex'; + +test('JES (engine status)', function (t) { + const x = '+RESP:GTJES,360303,864251020142968,,gv500,70007F,,1810,1172,27,20,74,41,0,0.0,117,128.4,37.578034,48.719447,20160818170736,,,,,,103.0,20160818170737,00DD$'; + const parsed = parse(x); + t.plan(18); + t.equal(parsed.imei, '864251020142968', 'imei') + t.equal(parsed.name, 'gv500', 'name'); + t.equal(parsed.jes.reportMask, parseInt('70007F', 16), 'report mask'); + t.ok(_.isNaN(parsed.jes.journeyConsumption)); + t.equal(parsed.jes.maxRPM, 1810, 'maxRPM'); + t.equal(parsed.jes.averageRPM, 1172, 'averageRPM'); + t.equal(parsed.jes.maxThrottlePosition, 27, 'maxThrottlePosition'); + t.equal(parsed.jes.averageThrottlePosition, 20, 'averageThrottlePosition'); + t.equal(parsed.jes.maxEngineLoad, 74, 'maxEngineLoad'); + t.equal(parsed.jes.averageEngineLoad, 41, 'averageEngineLoad'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 0.0, 'speed'); + t.equal(parsed.azimuth, 117, 'azimuth'); + t.equal(parsed.altitude, 128.4, 'altitude'); + t.equal(parsed.longitude, 37.578034); + t.equal(parsed.latitude, 48.719447); + t.equal(parsed.mileage, 103.0); + t.equal(decimalToHex(parsed.count, 4), '00DD', 'count'); +}) + + +test('Another JES (engine status)', function (t) { + const x = '+RESP:GTJES,360303,864251020143636,,gv500,70007F,,7942,4978,0,0,55,26,0,0.0,74,119.1,32.723300,50.514457,20160817162026,,,,,,103.1,20160817162027,0951$'; + const parsed = parse(x); + t.plan(18); + t.equal(parsed.imei, '864251020143636', 'imei') + t.equal(parsed.name, 'gv500', 'name'); + t.equal(parsed.jes.reportMask, parseInt('70007F', 16), 'report mask'); + t.ok(_.isNaN(parsed.jes.journeyConsumption), 'journeyConsumption'); + t.equal(parsed.jes.maxRPM, 7942, 'maxRPM'); + t.equal(parsed.jes.averageRPM, 4978, 'averageRPM'); + t.equal(parsed.jes.maxThrottlePosition, 0, 'maxThrottlePosition'); + t.equal(parsed.jes.averageThrottlePosition, 0, 'averageThrottlePosition'); + t.equal(parsed.jes.maxEngineLoad, 55, 'maxEngineLoad'); + t.equal(parsed.jes.averageEngineLoad, 26, 'averageEngineLoad'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 0.0, 'speed'); + t.equal(parsed.azimuth, 74, 'azimuth'); + t.equal(parsed.altitude, 119.1, 'altitude'); + t.equal(parsed.longitude, 32.723300); + t.equal(parsed.latitude, 50.514457); + t.equal(parsed.mileage, 103.1); + t.equal(decimalToHex(parsed.count, 4), '0951', 'count'); +}) diff --git a/src/test/obdeventparsertest.js b/src/test/obdeventparsertest.js new file mode 100644 index 0000000..d0ede08 --- /dev/null +++ b/src/test/obdeventparsertest.js @@ -0,0 +1,291 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import _ from 'lodash'; +import parse from '../helper/eventreportparser'; +import decimalToHex from '../listen/decimaltohex'; + + +test('OBD, 0 malfunctions, 1996 Jeep Grand Cherokee', function (t) { + const x = '+RESP:GTOBD,360100,864251020143040,,g5,0,79FFFF,,1,12510,983A8000,,,,,,,,,,,,,3,0,0,0.0,82,275.8,-93.295822,44.901657,20160323230656,0310,0260,74AF,AC5A,00,82.6,20160323230658,03EB$'; + const parsed = parse(x); + t.plan(28); + t.equal(parsed.name, 'g5', 'name'); + t.equal(parsed.imei, '864251020143040') + t.equal(parsed.reportMask, 7995391, 'report mask'); // 0x79FFFF + t.equal(parsed.obd.vin, '', 'obd VIN'); + t.equal(parsed.obd.connect, true, 'obd connected'); + t.equal(parsed.obd.powermV, 12510, 'obd powermv'); + t.equal(parsed.obd.supportPIDs, '983A8000', 'obd pids'); + t.ok(_.isNaN(parsed.obd.RPMs), 'obd rpms'); + t.ok(_.isNaN(parsed.obd.speed), 'obd speed'); + t.ok(_.isNaN(parsed.obd.temp), 'obd temp'); + t.ok(_.isNaN(parsed.obd.fuelConsumption), 'obd fuelConsumption'); + t.ok(_.isNaN(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage), 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.ok(_.isNaN(parsed.obd.malfunctionActivatedDistance), 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, false, 'obd manfunction'); + t.ok(_.isNaN(parsed.obd.diagnosticTroubleCodesCount), 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes.length, 0, 'obd diagnostic codes'); + t.ok(_.isNaN(parsed.obd.throttlePosition), 'obd throttle position'); + t.ok(_.isNaN(parsed.obd.engineLoad), 'obd throttle position'); + t.ok(_.isNaN(parsed.obd.fuelLevelInput), 'obd throttle position'); + t.equal(parsed.obd.mileage, 3, 'obd mileage'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 0, 'speed'); + t.equal(parsed.azimuth, 82, 'azimuth'); + t.equal(parsed.altitude, 275.8, 'altitude'); + t.equal(parsed.longitude, -93.295822); + t.equal(parsed.latitude, 44.901657); + t.equal(parsed.mileage, 82.6, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '03EB'); +}) + +test('OBD, 1 malfunction, 1996 Jeep Grand Cherokee', function (t) { + const x = '+RESP:GTOBD,360100,864251020143040,,g5,0,79FFFF,,1,13939,983A8000,777,0,56,inf,,,1,1,0138,12,5,,3,0,0,0.0,298,327.8,-93.296048,44.901821,20160323135025,0310,0260,74AF,AC5A,00,60.7,20160323135026,0379$'; + const parsed = parse(x); + t.plan(28); + t.equal(parsed.imei, '864251020143040', 'imei') + t.equal(parsed.name, 'g5', 'name'); + t.equal(parsed.reportMask, 7995391, 'report mask'); + t.equal(parsed.obd.vin, '', 'obd VIN'); + t.equal(parsed.obd.connect, true, 'obd connected'); + t.equal(parsed.obd.powermV, 13939, 'obd powermv'); + t.equal(parsed.obd.supportPIDs, '983A8000', 'obd pids'); + t.equal(parsed.obd.RPMs, 777, 'obd rpms'); + t.equal(parsed.obd.speed, 0, 'obd speed'); + t.equal(parsed.obd.temp, 56, 'obd coolant temp'); + t.equal(parsed.obd.fuelConsumption, Infinity, 'obd fuel consump'); + t.ok(_.isNaN(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage), 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.ok(_.isNaN(parsed.obd.malfunctionActivatedDistance), 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, true, 'obd manfunction'); + t.equal(parsed.obd.diagnosticTroubleCodesCount, 1, 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes[0], '0138', 'obd diagnostic codes'); + t.equal(parsed.obd.throttlePosition, 12, 'obd throttle position'); + t.equal(parsed.obd.engineLoad, 5, 'obd engine load'); + t.ok(_.isNaN(parsed.obd.fuelLevelInput), 'NaN fuel level input'); + t.equal(parsed.obd.mileage, 3, 'obd mileage'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 0, 'speed'); + t.equal(parsed.azimuth, 298, 'azimuth'); + t.equal(parsed.altitude, 327.8, 'altitude'); + t.equal(parsed.longitude, -93.296048, 'long'); + t.equal(parsed.latitude, 44.901821, 'lat'); + t.equal(parsed.mileage, 60.7, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '0379'); +}) + +test('parse OBD gv500', function (t) { + const x = '+BUFF:GTOBD,360100,864251020143727,,gv500,0,FFFF,,1,12617,,,,,,,,,,,,,,20160322195018,0108$'; + const parsed = parse(x); + t.plan(3); + t.equal(decimalToHex(parsed.count, 4), '0108'); + t.equal(parsed.imei, '864251020143727') + t.equal(parsed.name, 'gv500'); +}) + + +test('long OBD message 2 failure codes', function (t) { + const x = '+RESP:GTOBD,360100,864251020143040,,g5,0,79FFFF,,1,14022,983A8000,2031,102,96,3.8,,,1,2,0141,0138,25,23,,3,0,0,104.0,269,267.1,-93.269559,44.890825,20160326190646,0310,0260,74AF,A12F,00,155.6,20160326190649,05A6$' + const parsed = parse(x); + t.plan(30); + t.equal(parsed.imei, '864251020143040', 'imei') + t.equal(parsed.name, 'g5', 'name'); + t.equal(parsed.rty, '0', 'report type'); + t.equal(parsed.reportMask, 7995391, 'report mask'); + t.equal(parsed.obd.vin, '', 'obd vin'); + t.equal(parsed.obd.connect, true, 'odb connect'); + t.equal(parsed.obd.powermV, 14022, 'odb powermV'); + t.equal(parsed.obd.supportPIDs, '983A8000', 'support pids'); + t.equal(parsed.obd.RPMs, 2031, 'RPMs'); + t.equal(parsed.obd.speed, 102, 'OBD speed'); + t.equal(parsed.obd.temp, 96, 'OBD temp'); + t.equal(parsed.obd.fuelConsumption, 3.8, 'OBD fuel consumption'); + t.ok(_.isNaN(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage), 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.ok(_.isNaN(parsed.obd.malfunctionActivatedDistance), 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, true, 'OBD malfunction'); + t.equal(parsed.obd.diagnosticTroubleCodesCount, 2, 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes[0], '0141', 'OBD diagnosticTroubleCode 1'); + t.equal(parsed.obd.diagnosticTroubleCodes[1], '0138', 'OBD diagnosticTroubleCode 2'); + t.equal(parsed.obd.throttlePosition, 25, 'OBD throttlePosition'); + t.equal(parsed.obd.engineLoad, 23, 'engine load'); + t.ok(_.isNaN(parsed.obd.fuelLevelInput), 'fuel level input'); + t.equal(parsed.obd.mileage, 3, 'mileage'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 104.0, 'speed'); + t.equal(parsed.azimuth, 269, 'azimuth'); + t.equal(parsed.altitude, 267.1, 'altitude'); + t.equal(parsed.longitude, -93.269559, 'long'); + t.equal(parsed.latitude, 44.890825, 'lat'); + t.equal(parsed.mileage, 155.6, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '05A6', 'count'); +}) + +test('2 malfunctions but missing failure codes', function (t) { + const x = ' +RESP:GTOBD,360100,864251020143040,,g5,0,79FFFF,,1,13880,983A8000,1734,87,95,3.6,,,1,2,,21,18,,3,0,0,88.2,228,277.9,-93.325287,44.888686,20160327010551,0310,0260,74AF,9DB3,00,168.9,20160327010553,0618$'; + const parsed = parse(x); + t.plan(29); + t.equal(parsed.imei, '864251020143040', 'imei') + t.equal(parsed.name, 'g5', 'name'); + t.equal(parsed.rty, '0', 'report type'); + t.equal(parsed.reportMask, 7995391, 'report mask'); + t.equal(parsed.obd.vin, '', 'obd vin'); + t.equal(parsed.obd.connect, true, 'odb connect'); + t.equal(parsed.obd.powermV, 13880, 'odb powermV'); + t.equal(parsed.obd.supportPIDs, '983A8000', 'support pids'); + t.equal(parsed.obd.RPMs, 1734, 'RPMs'); + t.equal(parsed.obd.speed, 87, 'OBD speed'); + t.equal(parsed.obd.temp, 95, 'OBD temp'); + t.equal(parsed.obd.fuelConsumption, 3.6, 'OBD fuel consumption'); + t.ok(_.isNaN(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage), 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.ok(_.isNaN(parsed.obd.malfunctionActivatedDistance), 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, true, 'OBD malfunction'); + t.equal(parsed.obd.diagnosticTroubleCodesCount, 2, 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes.length,0 , 'OBD diagnosticTroubleCode length 0'); + t.equal(parsed.obd.throttlePosition, 21, 'OBD throttlePosition'); + t.equal(parsed.obd.engineLoad, 18, 'engine load'); + t.ok(_.isNaN(parsed.obd.fuelLevelInput), 'fuel level input'); + t.equal(parsed.obd.mileage, 3, 'mileage'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 88.2, 'speed'); + t.equal(parsed.azimuth, 228, 'azimuth'); + t.equal(parsed.altitude, 277.9, 'altitude'); + t.equal(parsed.longitude, -93.325287, 'long'); + t.equal(parsed.latitude, 44.888686, 'lat'); + t.equal(parsed.mileage, 168.9, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '0618', 'count'); +}) + +// +RESP:GTOBD,360100,864251020143040,,g5,0,79FFFF,,1,13872,983A8000,1661,56,96,,,,1,2,0141,0138,27,21,,3,0,0,89.8,1,281.9,-93.349840,44.896393,20160327010751,0310,0260,74B1,9CA7,00,171.6,20160327010753,061E$ +// +RESP:GTOBD,360100,864251020143040,,g5,0,79FFFF,,1,13853,983A8000,1610,85,99,2.4,,,1,2,0141,0138,24,21,,3,0,0,89.9,2,287.4,-93.349335,44.921277,20160327010951,0310,0260,74B1,B434,00,174.4,20160327010953,0620$ + +test('fuel level input Chevy Silverado', function (t) { + const x = '+RESP:GTOBD,360100,864251020143040,1GCEK19J48Z137290,g5,0,79FFFF,1GCEK19J48Z137290,1,14871,983B81E0,771,0,11,inf,24559,0,0,0,,25,29,38,6,0,0,,,,,,,0310,0260,74B1,9D83,00,278.8,20160327231033,072F$'; + const parsed = parse(x); + t.plan(23); + t.equal(parsed.imei, '864251020143040', 'imei') + t.equal(parsed.name, 'g5', 'name'); + t.equal(parsed.rty, '0', 'report type'); + t.equal(parsed.reportMask, 7995391, 'report mask'); + t.equal(parsed.obd.vin, '1GCEK19J48Z137290', 'obd vin'); + t.equal(parsed.obd.connect, true, 'odb connect'); + t.equal(parsed.obd.powermV, 14871, 'odb powermV'); + t.equal(parsed.obd.supportPIDs, '983B81E0', 'support pids'); + t.equal(parsed.obd.RPMs, 771, 'RPMs'); + t.equal(parsed.obd.speed, 0, 'OBD speed'); + t.equal(parsed.obd.temp, 11, 'OBD temp'); + t.equal(parsed.obd.fuelConsumption, Infinity, 'OBD fuel consumption'); + t.equal(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage, 24559, 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.equal(parsed.obd.malfunctionActivatedDistance, 0, 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, false, 'OBD malfunction'); + t.equal(parsed.obd.diagnosticTroubleCodesCount, 0, 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes.length,0 , 'OBD diagnosticTroubleCode length 0'); + t.equal(parsed.obd.throttlePosition, 25, 'OBD throttlePosition'); + t.equal(parsed.obd.engineLoad, 29, 'engine load'); + t.equal(parsed.obd.fuelLevelInput, 38, 'fuel level input'); + t.equal(parsed.obd.mileage, 6, 'mileage'); + t.equal(parsed.mileage, 278.8, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '072F', 'count'); +}) + +test('another fuel level input Lincoln MKZ', function (t) { + const x = '+RESP:GTOBD,360100,864251020143040,3LNHL2GC4BR773283,g5,0,79FFFF,3LNHL2GC4BR773283,1,14312,981B81E0,1333,0,8,,65535,0,0,0,,17,49,58,6,40976,0,0.0,0,288.9,-93.399623,44.940529,20160327232242,0310,0260,74B1,9D83,00,278.8,20160327232512,0731$'; + const parsed = parse(x); + t.plan(29); + t.equal(parsed.imei, '864251020143040', 'imei') + t.equal(parsed.name, 'g5', 'name'); + t.equal(parsed.rty, '0', 'report type'); + t.equal(parsed.reportMask, 7995391, 'report mask'); + t.equal(parsed.obd.vin, '3LNHL2GC4BR773283', 'obd vin'); + t.equal(parsed.obd.connect, true, 'odb connect'); + t.equal(parsed.obd.powermV, 14312, 'odb powermV'); + t.equal(parsed.obd.supportPIDs, '981B81E0', 'support pids'); + t.equal(parsed.obd.RPMs, 1333, 'RPMs'); + t.equal(parsed.obd.speed, 0, 'OBD speed'); + t.equal(parsed.obd.temp, 8, 'OBD temp'); + t.ok(_.isNaN(parsed.obd.fuelConsumption), 'OBD fuel consumption'); + t.equal(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage, 65535, 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.equal(parsed.obd.malfunctionActivatedDistance, 0, 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, false, 'OBD malfunction'); + t.equal(parsed.obd.diagnosticTroubleCodesCount, 0, 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes.length,0 , 'OBD diagnosticTroubleCode length 0'); + t.equal(parsed.obd.throttlePosition, 17, 'OBD throttlePosition'); + t.equal(parsed.obd.engineLoad, 49, 'engine load'); + t.equal(parsed.obd.fuelLevelInput, 58, 'fuel level input'); + t.equal(parsed.obd.mileage, 6, 'mileage'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 0, 'speed'); + t.equal(parsed.azimuth, 0, 'azimuth'); + t.equal(parsed.altitude, 288.9, 'altitude'); + t.equal(parsed.longitude, -93.399623, 'long'); + t.equal(parsed.latitude, 44.940529, 'lat'); + t.equal(parsed.mileage, 278.8, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '0731', 'count'); +}) + +test('Honda CRV OBD 360303', function (t) { + const parsed = parse('+RESP:GTOBD,360303,864251020143594,,gv500,0,79FFFF,,1,14125,983A8000,2682,72,91,22.9,,,1,4,1259032501710133,26,68,,3,1,0,80.2,66,65.9,37.521339,49.030879,20161017124818,,,,,,31.3,20161017124821,0150$'); + t.plan(29); + t.equal(parsed.imei, '864251020143594', 'imei') + t.equal(parsed.name, 'gv500', 'name'); + t.equal(parsed.rty, '0', 'report type'); + t.equal(parsed.reportMask, parseInt('79FFFF', 16), 'report mask'); + t.equal(parsed.obd.vin, '', 'obd vin'); + t.equal(parsed.obd.connect, true, 'odb connect'); + t.equal(parsed.obd.powermV, 14125, 'odb powermV'); + t.equal(parsed.obd.supportPIDs, '983A8000', 'support pids'); + t.equal(parsed.obd.RPMs, 2682, 'RPMs'); + t.equal(parsed.obd.speed, 72, 'OBD speed'); + t.equal(parsed.obd.temp, 91, 'OBD temp'); + t.equal(parsed.obd.fuelConsumption, 22.9, 'OBD fuel consumption'); + t.ok(_.isNaN(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage), 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.ok(_.isNaN(parsed.obd.malfunctionActivatedDistance), 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, true, 'OBD malfunction'); + t.equal(parsed.obd.diagnosticTroubleCodesCount, 4, 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes.length, 4, 'OBD diagnosticTroubleCode length 4'); + t.equal(parsed.obd.throttlePosition, 26, 'OBD throttlePosition'); + t.equal(parsed.obd.engineLoad, 68, 'engine load'); + t.ok(_.isNaN(parsed.obd.fuelLevelInput), 'fuel level input'); + t.equal(parsed.obd.mileage, 3, 'mileage'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 80.2, 'speed'); + t.equal(parsed.azimuth, 66, 'azimuth'); + t.equal(parsed.altitude, 65.9, 'altitude'); + t.equal(parsed.longitude, 37.521339, 'long'); + t.equal(parsed.latitude, 49.030879, 'lat'); + t.equal(parsed.mileage, 31.3, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '0150', 'count'); +}) + +test('Honda CRV OBD new firmware', function (t) { + const parsed = parse('+RESP:GTOBD,360402,864251020143594,,gv500,0,79FFFF,,1,14360,983A8000,1709,34,87,23.4,,,1,4,1259032501710133,20,65,,3,1,0,41.6,355,73.9,37.511269,49.018711,20161018123455,,,,,,62.8,20161018123458,002C$'); + t.plan(29); + t.equal(parsed.imei, '864251020143594', 'imei') + t.equal(parsed.name, 'gv500', 'name'); + t.equal(parsed.rty, '0', 'report type'); + t.equal(parsed.reportMask, parseInt('79FFFF', 16), 'report mask'); + t.equal(parsed.obd.vin, '', 'obd vin'); + t.equal(parsed.obd.connect, true, 'odb connect'); + t.equal(parsed.obd.powermV, 14360, 'odb powermV'); + t.equal(parsed.obd.supportPIDs, '983A8000', 'support pids'); + t.equal(parsed.obd.RPMs, 1709, 'RPMs'); + t.equal(parsed.obd.speed, 34, 'OBD speed'); + t.equal(parsed.obd.temp, 87, 'OBD temp'); + t.equal(parsed.obd.fuelConsumption, 23.4, 'OBD fuel consumption'); + t.ok(_.isNaN(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage), 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.ok(_.isNaN(parsed.obd.malfunctionActivatedDistance), 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, true, 'OBD malfunction'); + t.equal(parsed.obd.diagnosticTroubleCodesCount, 4, 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes.length, 4, 'OBD diagnosticTroubleCode length 4'); + t.equal(parsed.obd.throttlePosition, 20, 'OBD throttlePosition'); + t.equal(parsed.obd.engineLoad, 65, 'engine load'); + t.ok(_.isNaN(parsed.obd.fuelLevelInput), 'fuel level input'); + t.equal(parsed.obd.mileage, 3, 'mileage'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 41.6, 'speed'); + t.equal(parsed.azimuth, 355, 'azimuth'); + t.equal(parsed.altitude, 73.9, 'altitude'); + t.equal(parsed.longitude, 37.511269, 'long'); + t.equal(parsed.latitude, 49.018711, 'lat'); + t.equal(parsed.mileage, 62.8, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '002C', 'count'); +}) diff --git a/src/test/osmeventparsertest.js b/src/test/osmeventparsertest.js new file mode 100644 index 0000000..e7c0371 --- /dev/null +++ b/src/test/osmeventparsertest.js @@ -0,0 +1,118 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import _ from 'lodash'; +import parse from '../helper/eventreportparser'; +import decimalToHex from '../listen/decimaltohex'; + + +test('OSM message, no failure codes', function (t) { + const x = '+RESP:GTOSM,360100,864251020143727,,gv500,3,0,78FFFF,WVGZZZ1TZCW092623,1,14402,983A81C0,1605,37,86,13.8,3087,0,0,0,,15,22,,21,0,40.7,299,136.2,37.579901,48.720192,20160324142307,,,,,,0.0,20160324142309,0A98$' + const parsed = parse(x); + t.plan(30); + t.equal(parsed.imei, '864251020143727', 'imei') + t.equal(parsed.name, 'gv500', 'name'); + t.equal(parsed.rid, '3', 'record id'); + t.equal(parsed.rty, '0', 'report type'); + t.equal(parsed.reportMask, 7929855, 'report mask'); // 0x78FFFF + t.equal(parsed.obd.vin, 'WVGZZZ1TZCW092623', 'obd vin'); + t.equal(parsed.obd.connect, true, 'odb connect'); + t.equal(parsed.obd.powermV, 14402, 'odb powermV'); + t.equal(parsed.obd.supportPIDs, '983A81C0', 'support pids'); + t.equal(parsed.obd.RPMs, 1605, 'RPMs'); + t.equal(parsed.obd.speed, 37, 'OBD speed'); + t.equal(parsed.obd.temp, 86, 'OBD temp'); + t.equal(parsed.obd.fuelConsumption, 13.8, 'OBD fuel consumption'); + t.equal(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage, 3087, 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.equal(parsed.obd.malfunctionActivatedDistance, 0, 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, false, 'OBD malfunction'); + t.equal(parsed.obd.diagnosticTroubleCodesCount, 0, 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes.length, 0, 'OBD diagnosticTroubleCodes'); + t.equal(parsed.obd.throttlePosition, 15, 'OBD throttlePosition'); + t.equal(parsed.obd.engineLoad, 22, 'engine load'); + t.ok(_.isNaN(parsed.obd.fuelLevelInput), 'fuel level input'); + t.equal(parsed.obd.mileage, 21, 'mileage'); + t.equal(parsed.accuracy, 0, 'accuracy'); + t.equal(parsed.speed, 40.7, 'speed'); + t.equal(parsed.azimuth, 299, 'azimuth'); + t.equal(parsed.altitude, 136.2, 'altitude'); + t.equal(parsed.longitude, 37.579901, 'long'); + t.equal(parsed.latitude, 48.720192, 'lat'); + t.equal(parsed.mileage, 0, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '0A98', 'count'); +}) + + +test('parse short OSM message', function (t) { + const x = '+RESP:GTOSM,360100,864251020143727,,gv500,0,0,FFFF,WVGZZZ1TZCW092623,1,14436,983A81C0,782,0,86,inf,3087,0,0,0,,11,12,,20160324142335,0A9B$' + const parsed = parse(x); + t.plan(4); + t.equal(decimalToHex(parsed.count, 4), '0A9B'); + t.equal(parsed.imei, '864251020143727') + t.equal(parsed.name, 'gv500'); + t.equal(parsed.obd.vin, 'WVGZZZ1TZCW092623'); +}) + + +test('another OSM no failure codes', function (t) { + const x = '+RESP:GTOSM,360100,864251020143727,,gv500,0,0,FFFF,WVGZZZ1TZCW092623,1,14459,983A81C0,1015,0,20,inf,3066,0,0,0,,13,18,,20160324100329,0899$'; + const parsed = parse(x); + t.plan(22); + t.equal(parsed.imei, '864251020143727', 'imei') + t.equal(parsed.name, 'gv500', 'name'); + t.equal(parsed.rid, '0', 'record id'); + t.equal(parsed.rty, '0', 'report type'); + t.equal(parsed.reportMask, 65535, 'report mask'); + t.equal(parsed.obd.vin, 'WVGZZZ1TZCW092623', 'obd vin'); + t.equal(parsed.obd.connect, true, 'odb connect'); + t.equal(parsed.obd.powermV, 14459, 'odb powermV'); + t.equal(parsed.obd.supportPIDs, '983A81C0', 'support pids'); + t.equal(parsed.obd.RPMs, 1015, 'RPMs'); + t.equal(parsed.obd.speed, 0, 'OBD speed'); + t.equal(parsed.obd.temp, 20, 'OBD temp'); + t.equal(parsed.obd.fuelConsumption, Infinity, 'OBD fuel consumption'); + t.equal(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage, 3066, 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + t.equal(parsed.obd.malfunctionActivatedDistance, 0, 'OBD malfunctionActivatedDistance'); + t.equal(parsed.obd.malfunction, false, 'OBD malfunction'); + t.equal(parsed.obd.diagnosticTroubleCodesCount, 0, 'OBD diagnosticTroubleCodesCount'); + t.equal(parsed.obd.diagnosticTroubleCodes.length, 0, 'OBD diagnosticTroubleCodes'); + t.equal(parsed.obd.throttlePosition, 13, 'OBD throttlePosition'); + t.equal(parsed.obd.engineLoad, 18, 'engine load'); + t.ok(_.isNaN(parsed.obd.fuelLevelInput), 'fuel level input'); + // t.equal(parsed.obd.mileage, 21, 'mileage'); + // t.equal(parsed.accuracy, 0, 'accuracy'); + // t.equal(parsed.speed, 40.7, 'speed'); + // t.equal(parsed.azimuth, 299, 'azimuth'); + // t.equal(parsed.altitude, 136.2, 'altitude'); + // t.equal(parsed.longitude, 37.579901, 'long'); + // t.equal(parsed.latitude, 48.720192, 'lat'); + // t.equal(parsed.mileage, 0, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '0899', 'count'); +}) + + +test('was parsing incorrect azimuth on OSM message', function (t) { + const parsed = parse('+RESP:GTOSM,360100,864251020145193,,,8,0,C0D0,1429,89,,21,94,20160406221831,01F3$'); + t.plan(8) + t.equal(parsed.azimuth, undefined, 'no azimuth'); + t.equal(parsed.reportMask, parseInt('C0D0', 16), 'reportMask'); + t.equal(parsed.obd.RPMs, 1429, 'RPMs'); + t.equal(parsed.obd.temp, 89, 'temp'); + t.ok(_.isNaN(parsed.obd.fuelConsumption), 'fuelConsumption NaN'); + t.equal(parsed.obd.engineLoad, 21, 'engineLoad'); + t.equal(parsed.obd.fuelLevelInput, 94, 'fuelLevelInput'); + t.equal(decimalToHex(parsed.count, 4), '01F3', 'count'); +}) + +test('Mazda OSM', function (t) { + const parsed = parse('+RESP:GTOSM,360100,864251020145193,,,8,0,C0D0,2039,86,15.5,78,38,20160408201518,0557$'); + t.plan(8) + t.equal(parsed.azimuth, undefined, 'no azimuth'); + t.equal(parsed.reportMask, parseInt('C0D0', 16), 'reportMask'); + t.equal(parsed.obd.RPMs, 2039, 'RPMs'); + t.equal(parsed.obd.temp, 86, 'temp'); + t.equal(parsed.obd.fuelConsumption, 15.5, 'fuelConsumption'); + t.equal(parsed.obd.engineLoad, 78, 'engineLoad'); + t.equal(parsed.obd.fuelLevelInput, 38, 'fuelLevelInput'); + t.equal(decimalToHex(parsed.count, 4), '0557', 'count'); +}) diff --git a/src/test/reports/apr3.json b/src/test/reports/apr3.json new file mode 100644 index 0000000..5548fa2 --- /dev/null +++ b/src/test/reports/apr3.json @@ -0,0 +1,10280 @@ +[ + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T05:03:04.000Z", + "g": 0, + "id": "20160403050304000|864251020142968|183D", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12525, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:04:55.000Z", + "g": 1, + "h": "", + "id": "20160403050455000|864251020142968|183E", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:09:54.000Z", + "g": 1, + "h": "", + "id": "20160403050954000|864251020142968|1840", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T05:13:02.000Z", + "g": 0, + "id": "20160403051302000|864251020142968|1842", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12525, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:14:53.000Z", + "g": 1, + "h": "", + "id": "20160403051453000|864251020142968|1843", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:19:52.000Z", + "g": 1, + "h": "", + "id": "20160403051952000|864251020142968|1845", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T05:23:00.000Z", + "g": 0, + "id": "20160403052300000|864251020142968|1847", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12531, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:24:52.000Z", + "g": 1, + "h": "", + "id": "20160403052452000|864251020142968|1848", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:29:51.000Z", + "g": 1, + "h": "", + "id": "20160403052951000|864251020142968|184A", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T05:32:58.000Z", + "g": 0, + "id": "20160403053258000|864251020142968|184C", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12526, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:34:50.000Z", + "g": 1, + "h": "", + "id": "20160403053450000|864251020142968|184D", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:39:50.000Z", + "g": 1, + "h": "", + "id": "20160403053950000|864251020142968|184F", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T05:42:56.000Z", + "g": 0, + "id": "20160403054256000|864251020142968|1852", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12525, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:44:49.000Z", + "g": 1, + "h": "", + "id": "20160403054449000|864251020142968|1853", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:49:48.000Z", + "g": 1, + "h": "", + "id": "20160403054948000|864251020142968|1855", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T05:52:55.000Z", + "g": 0, + "id": "20160403055255000|864251020142968|1857", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12521, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:54:48.000Z", + "g": 1, + "h": "", + "id": "20160403055448000|864251020142968|1858", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T05:59:47.000Z", + "g": 1, + "h": "", + "id": "20160403055947000|864251020142968|185A", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T06:02:53.000Z", + "g": 0, + "id": "20160403060253000|864251020142968|185B", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12557, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:04:46.000Z", + "g": 1, + "h": "", + "id": "20160403060446000|864251020142968|185D", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:09:46.000Z", + "g": 1, + "h": "", + "id": "20160403060946000|864251020142968|185F", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T06:12:51.000Z", + "g": 0, + "id": "20160403061251000|864251020142968|1860", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12556, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:14:45.000Z", + "g": 1, + "h": "", + "id": "20160403061445000|864251020142968|1862", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:19:44.000Z", + "g": 1, + "h": "", + "id": "20160403061944000|864251020142968|1864", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T06:22:49.000Z", + "g": 0, + "id": "20160403062249000|864251020142968|1866", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12516, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:24:44.000Z", + "g": 1, + "h": "", + "id": "20160403062444000|864251020142968|1867", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:29:43.000Z", + "g": 1, + "h": "", + "id": "20160403062943000|864251020142968|1869", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T06:32:47.000Z", + "g": 0, + "id": "20160403063247000|864251020142968|186B", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12499, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:34:42.000Z", + "g": 1, + "h": "", + "id": "20160403063442000|864251020142968|186C", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:39:42.000Z", + "g": 1, + "h": "", + "id": "20160403063942000|864251020142968|186E", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T06:42:45.000Z", + "g": 0, + "id": "20160403064245000|864251020142968|1871", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12499, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:44:41.000Z", + "g": 1, + "h": "", + "id": "20160403064441000|864251020142968|1872", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:49:40.000Z", + "g": 1, + "h": "", + "id": "20160403064940000|864251020142968|1874", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T06:52:43.000Z", + "g": 0, + "id": "20160403065243000|864251020142968|1876", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12497, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:54:40.000Z", + "g": 1, + "h": "", + "id": "20160403065440000|864251020142968|1877", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T06:59:39.000Z", + "g": 1, + "h": "", + "id": "20160403065939000|864251020142968|1879", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T07:02:42.000Z", + "g": 0, + "id": "20160403070242000|864251020142968|187B", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12498, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:04:38.000Z", + "g": 1, + "h": "", + "id": "20160403070438000|864251020142968|187C", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:09:37.000Z", + "g": 1, + "h": "", + "id": "20160403070937000|864251020142968|187E", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T07:12:40.000Z", + "g": 0, + "id": "20160403071240000|864251020142968|1880", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12497, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:14:37.000Z", + "g": 1, + "h": "", + "id": "20160403071437000|864251020142968|1881", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:19:36.000Z", + "g": 1, + "h": "", + "id": "20160403071936000|864251020142968|1883", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T07:22:38.000Z", + "g": 0, + "id": "20160403072238000|864251020142968|1885", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12498, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:24:35.000Z", + "g": 1, + "h": "", + "id": "20160403072435000|864251020142968|1886", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:29:35.000Z", + "g": 1, + "h": "", + "id": "20160403072935000|864251020142968|1888", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T07:32:36.000Z", + "g": 0, + "id": "20160403073236000|864251020142968|188A", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12498, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:34:34.000Z", + "g": 1, + "h": "", + "id": "20160403073434000|864251020142968|188B", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:39:34.000Z", + "g": 1, + "h": "", + "id": "20160403073934000|864251020142968|188D", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T07:42:34.000Z", + "g": 0, + "id": "20160403074234000|864251020142968|1890", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12496, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:44:33.000Z", + "g": 1, + "h": "", + "id": "20160403074433000|864251020142968|1891", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:49:32.000Z", + "g": 1, + "h": "", + "id": "20160403074932000|864251020142968|1893", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T07:52:32.000Z", + "g": 0, + "id": "20160403075232000|864251020142968|1895", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12497, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:54:32.000Z", + "g": 1, + "h": "", + "id": "20160403075432000|864251020142968|1896", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T07:59:31.000Z", + "g": 1, + "h": "", + "id": "20160403075931000|864251020142968|1898", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T08:02:31.000Z", + "g": 0, + "id": "20160403080231000|864251020142968|189A", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12496, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:04:30.000Z", + "g": 1, + "h": "", + "id": "20160403080430000|864251020142968|189B", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:09:30.000Z", + "g": 1, + "h": "", + "id": "20160403080930000|864251020142968|189D", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T08:12:29.000Z", + "g": 0, + "id": "20160403081229000|864251020142968|189F", + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12496, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:14:29.000Z", + "faketow": true, + "g": 1, + "h": "", + "id": "20160403081429000|864251020142968|18A0", + "ig": false, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJfdjAwZi-30ARrmjO-R5ItdA", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Bohdana Khmelnytskoho St, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6327878, + "longitude": 37.5338964, + "streetName": "Bohdana Khmelnytskoho Street" + }, + "cmd": "IGN", + "d": "2016-04-03T08:16:17.000Z", + "g": 0, + "h": "", + "id": "20160403081617000|864251020142968|18A1", + "igd": 88159, + "la": 48.633019, + "lo": 37.533962, + "m": 0, + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "cmd": "PFA", + "d": "2016-04-03T08:16:18.000Z", + "id": "20160403081618000|864251020142968|18A2", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "cmd": "PNA", + "d": "2016-04-03T08:16:29.000Z", + "id": "20160403081629000|864251020142968|18A3", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "cmd": "MPN", + "d": "2016-04-03T08:16:30.000Z", + "g": 0, + "id": "20160403081630000|864251020142968|18A4", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "cmd": "OPN", + "d": "2016-04-03T08:16:32.000Z", + "g": 0, + "id": "20160403081632000|864251020142968|18A5", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "cmd": "IGN", + "d": "2016-04-03T08:16:49.000Z", + "g": 0, + "h": "", + "id": "20160403081649000|864251020142968|18A7", + "igd": 0, + "m": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 356, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJffbujZy-30ARkCV46x4PjZY", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "H20, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6388087, + "longitude": 37.5384078, + "streetName": "H20" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:16:55.000Z", + "g": 3, + "h": "", + "id": "20160403081655000|864251020142968|18A9", + "ig": true, + "la": 48.63863, + "lo": 37.538534, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 68, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 356, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Druzhkivs'ka city council", + "level3short": "Druzhkivs'ka city council" + }, + "city": "Druzhkivka", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJUZhMw5y-30AR2EEBkY_WocY", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "H20, Druzhkivka, Donetsk Oblast, Ukraine", + "latitude": 48.6399522, + "longitude": 37.5383216, + "streetName": "H20" + }, + "cmd": "OBD", + "d": "2016-04-03T08:17:02.000Z", + "g": 0, + "id": "20160403081702000|864251020142968|18AA", + "la": 48.639647, + "lo": 37.538499, + "m": 0, + "obd": { + "RPMs": 1685, + "connect": true, + "diagnosticTroubleCodes": [], + "diagnosticTroubleCodesCount": 1, + "engineLoad": 64, + "malfunction": false, + "malfunctionActivatedDistance": 244, + "mileage": 0, + "powermV": 14129, + "speed": 72, + "supportPIDs": "981B81C0", + "temp": 220, + "throttlePosition": 25, + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 65.5, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 351, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast" + }, + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJK0S9sM2930AR7BeIQv9gsw8", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "H20, Donetsk Oblast, Ukraine", + "latitude": 48.6582194, + "longitude": 37.5342437, + "streetName": "H20" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:18:55.000Z", + "g": 1, + "h": "", + "id": "20160403081855000|864251020142968|18AC", + "ig": true, + "la": 48.657473, + "lo": 37.534472, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 79.2, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 37, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast" + }, + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJ15Y2isa930ARblaFX3jDffM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "H20, Donetsk Oblast, Ukraine", + "latitude": 48.6674589, + "longitude": 37.538869, + "streetName": "H20" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:19:37.000Z", + "g": 1, + "h": "", + "id": "20160403081937000|864251020142968|18AF", + "ig": true, + "la": 48.665802, + "lo": 37.535773, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 84.6, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 63, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJzZ--OsK930ARzzFsVPU-dc0", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "H20, Donetsk Oblast, Ukraine", + "latitude": 48.6703227, + "longitude": 37.5478303, + "streetName": "H20" + }, + "cmd": "OBD", + "d": "2016-04-03T08:20:22.000Z", + "g": 0, + "id": "20160403082022000|864251020142968|18B0", + "la": 48.670254, + "lo": 37.547825, + "m": 0, + "obd": { + "RPMs": 1745, + "connect": true, + "diagnosticTroubleCodes": [], + "diagnosticTroubleCodesCount": 1, + "engineLoad": 82, + "malfunction": false, + "malfunctionActivatedDistance": 244, + "mileage": 0, + "powermV": 14128, + "speed": 85, + "supportPIDs": "981B81C0", + "temp": 220, + "throttlePosition": 29, + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 91.5, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 63, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJ_X0SH-m930ARySimz4-sR9c", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "H20, Donetsk Oblast, Ukraine", + "latitude": 48.6732075, + "longitude": 37.5565668, + "streetName": "H20" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:20:55.000Z", + "g": 1, + "h": "", + "id": "20160403082055000|864251020142968|18B2", + "ig": true, + "la": 48.673955, + "lo": 37.558742, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 102.5, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 21, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJH_SJ3vO930ARQvR0jRlyU10", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "H20, Donetsk Oblast, Ukraine", + "latitude": 48.6818184, + "longitude": 37.5650863, + "streetName": "H20" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:21:19.000Z", + "g": 1, + "h": "", + "id": "20160403082119000|864251020142968|18B5", + "ig": true, + "la": 48.677818, + "lo": 37.565516, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 85.9, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 19, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJIwGUCyCW30ARFh64Fh8mdZs", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "H20, Donetsk Oblast, Ukraine", + "latitude": 48.6899908, + "longitude": 37.5638756, + "streetName": "H20" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:22:55.000Z", + "g": 1, + "h": "", + "id": "20160403082255000|864251020142968|18B7", + "ig": true, + "la": 48.691008, + "lo": 37.563862, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 354, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJl7IHUiSW30ARErkZHd4Rbqc", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Tankistiv St, 101, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.698049, + "longitude": 37.56292699999999, + "streetName": "Tankistiv Street", + "streetNumber": "101" + }, + "cmd": "OBD", + "d": "2016-04-03T08:23:41.000Z", + "g": 0, + "id": "20160403082341000|864251020142968|18B8", + "la": 48.697455, + "lo": 37.562854, + "m": 0, + "obd": { + "RPMs": 606, + "connect": true, + "diagnosticTroubleCodes": [], + "diagnosticTroubleCodesCount": 1, + "engineLoad": 50, + "malfunction": false, + "malfunctionActivatedDistance": 244, + "mileage": 0, + "powermV": 14010, + "speed": 0, + "supportPIDs": "981B81C0", + "temp": 220, + "throttlePosition": 23, + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 75.9, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 335, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ2Uj1BjGW30ARwIzRa5kqXvY", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Tankistiv St, 29, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.705314, + "longitude": 37.561773, + "streetName": "Tankistiv Street", + "streetNumber": "29" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:24:22.000Z", + "g": 1, + "h": "", + "id": "20160403082422000|864251020142968|18BB", + "ig": true, + "la": 48.705328, + "lo": 37.561228, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 83.7, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 355, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJNef1gzOW30ARrA8_Wjfo2Bk", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Tankistiv St, 42, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.708894, + "longitude": 37.558185, + "streetName": "Tankistiv Street", + "streetNumber": "42" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:24:54.000Z", + "g": 1, + "h": "", + "id": "20160403082454000|864251020142968|18BD", + "ig": true, + "la": 48.710978, + "lo": 37.557781, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 76.7, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 14, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJNef1gzOW30ARrA8_Wjfo2Bk", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Tankistiv St, 42, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.708894, + "longitude": 37.558185, + "streetName": "Tankistiv Street", + "streetNumber": "42" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:25:01.000Z", + "g": 1, + "h": "", + "id": "20160403082501000|864251020142968|18C0", + "ig": true, + "la": 48.712698, + "lo": 37.558091, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 73.4, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 17, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJGU1COK6X30ARjvbPDnovMZI", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Аероклубна, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7259323, + "longitude": 37.5640711, + "streetName": "вулиця Аероклубна" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:26:54.000Z", + "g": 1, + "h": "", + "id": "20160403082654000|864251020142968|18C2", + "ig": true, + "la": 48.726075, + "lo": 37.563877, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 36.2, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 19, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJVZJ9Uq6X30ARbNPkRbHXl0Q", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Oleksy Tykhoho St, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7269059, + "longitude": 37.5641391, + "streetName": "Oleksy Tykhoho Street" + }, + "cmd": "OBD", + "d": "2016-04-03T08:27:00.000Z", + "g": 0, + "id": "20160403082700000|864251020142968|18C3", + "la": 48.726762, + "lo": 37.564206, + "m": 0, + "obd": { + "RPMs": 1502, + "connect": true, + "diagnosticTroubleCodes": [], + "diagnosticTroubleCodesCount": 1, + "engineLoad": 62, + "malfunction": false, + "malfunctionActivatedDistance": 244, + "mileage": 0, + "powermV": 13863, + "speed": 21, + "supportPIDs": "981B81C0", + "temp": 220, + "throttlePosition": 25, + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 57.9, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 77, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJBca4MgaX30AR-5bz24ketWc", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Parkova St, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7357355, + "longitude": 37.57352849999999, + "streetName": "Parkova Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:28:10.000Z", + "g": 1, + "h": "", + "id": "20160403082810000|864251020142968|18C6", + "ig": true, + "la": 48.736493, + "lo": 37.571399, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 20.6, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 119, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.7, + "establishment": null, + "googlePlaceId": "ChIJBca4MgaX30AR-pbz24ketWc", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Parkova St, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7357355, + "longitude": 37.57352849999999, + "streetName": "Parkova Street" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:28:16.000Z", + "g": 1, + "h": "", + "id": "20160403082816000|864251020142968|18C9", + "ig": true, + "la": 48.736303, + "lo": 37.57198, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 37.4, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 118, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJYexI0AaX30ARh4RJZ2fLvwU", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Parkova St, 9, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7340379, + "longitude": 37.5792181, + "streetName": "Parkova Street", + "streetNumber": "9", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:28:54.000Z", + "g": 1, + "h": "", + "id": "20160403082854000|864251020142968|18CB", + "ig": true, + "la": 48.733816, + "lo": 37.578823, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 66.3, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 118, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJj6TSRP6W30ARWMz-OnsBRXU", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Parkova St, 55, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.73042179999999, + "longitude": 37.5895661, + "streetName": "Parkova Street", + "streetNumber": "55", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T08:30:20.000Z", + "g": 0, + "id": "20160403083020000|864251020142968|18CC", + "la": 48.729829, + "lo": 37.589833, + "m": 0, + "obd": { + "RPMs": 1771, + "connect": true, + "diagnosticTroubleCodes": [], + "diagnosticTroubleCodesCount": 1, + "engineLoad": 84, + "malfunction": false, + "malfunctionActivatedDistance": 244, + "mileage": 0, + "powermV": 13653, + "speed": 49, + "supportPIDs": "981B81C0", + "temp": 220, + "throttlePosition": 33, + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 30.1, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 60, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJLfJCWf6W30AR_jgGVk-4-UI", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.730268, + "longitude": 37.590113, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:30:40.000Z", + "g": 1, + "h": "", + "id": "20160403083040000|864251020142968|18CF", + "ig": true, + "la": 48.729791, + "lo": 37.590115, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 12.4, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 25, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJhZN7Zv6W30ARbudat48134w", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 70, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7308782, + "longitude": 37.5905706, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "70", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:30:53.000Z", + "g": 1, + "h": "", + "id": "20160403083053000|864251020142968|18D1", + "ig": true, + "la": 48.730767, + "lo": 37.590881, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 45.5, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 13, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ44zvnv2W30ARxPpqhCwlx3Y", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 48, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.733766, + "longitude": 37.592987, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "48" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:31:16.000Z", + "g": 2, + "h": "", + "id": "20160403083116000|864251020142968|18D4", + "ig": true, + "la": 48.733343, + "lo": 37.59295, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 15.8, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 317, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ44zvnv2W30ARxPpqhCwlx3Y", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 48, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.733766, + "longitude": 37.592987, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "48" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:31:22.000Z", + "g": 1, + "h": "", + "id": "20160403083122000|864251020142968|18D7", + "ig": true, + "la": 48.733455, + "lo": 37.592872, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 15.4, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 232, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJLbh3lP2W30ARuC8URhZ9igM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7332639, + "longitude": 37.5918207, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:31:43.000Z", + "g": 1, + "h": "", + "id": "20160403083143000|864251020142968|18DA", + "ig": true, + "la": 48.733993, + "lo": 37.591012, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 12.5, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 177, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:31:58.000Z", + "g": 1, + "h": "", + "id": "20160403083158000|864251020142968|18DD", + "ig": true, + "la": 48.733606, + "lo": 37.590584, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 9.5, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:32:53.000Z", + "g": 2, + "h": "", + "id": "20160403083253000|864251020142968|18DF", + "ig": true, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "cmd": "JES", + "d": "2016-04-03T08:32:56.000Z", + "id": "20160403083256000|864251020142968|18E0", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "cmd": "IGF", + "d": "2016-04-03T08:32:56.000Z", + "g": 0, + "h": "", + "id": "20160403083256000|864251020142968|18E1", + "igd": 967, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T08:32:58.000Z", + "g": 0, + "id": "20160403083258000|864251020142968|18E2", + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12014, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:33:00.000Z", + "g": 1, + "h": "", + "id": "20160403083300000|864251020142968|18E4", + "ig": false, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:38:29.000Z", + "g": 1, + "h": "", + "id": "20160403083829000|864251020142968|18E6", + "ig": false, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T08:42:57.000Z", + "g": 0, + "id": "20160403084257000|864251020142968|18E8", + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12763, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:43:29.000Z", + "g": 1, + "h": "", + "id": "20160403084329000|864251020142968|18E9", + "ig": false, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:48:28.000Z", + "g": 1, + "h": "", + "id": "20160403084828000|864251020142968|18EB", + "ig": false, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T08:52:55.000Z", + "g": 0, + "id": "20160403085255000|864251020142968|18ED", + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12704, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:53:27.000Z", + "g": 1, + "h": "", + "id": "20160403085327000|864251020142968|18EE", + "ig": false, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T08:58:27.000Z", + "g": 1, + "h": "", + "id": "20160403085827000|864251020142968|18F0", + "ig": false, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T09:02:53.000Z", + "g": 0, + "id": "20160403090253000|864251020142968|18F2", + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12674, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:03:26.000Z", + "g": 1, + "h": "", + "id": "20160403090326000|864251020142968|18F3", + "ig": false, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:08:25.000Z", + "g": 1, + "h": "", + "id": "20160403090825000|864251020142968|18F5", + "ig": false, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T09:12:51.000Z", + "g": 0, + "id": "20160403091251000|864251020142968|18F7", + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12644, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:13:25.000Z", + "g": 1, + "h": "", + "id": "20160403091325000|864251020142968|18F8", + "ig": false, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 147, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJH7bb8_2W30AR6BGSHq36SdM", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "ulitsa Yaroslava Mudrogo, 56А, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.7331144, + "longitude": 37.5906014, + "streetName": "ulitsa Yaroslava Mudrogo", + "streetNumber": "56А", + "zipcode": "84300" + }, + "cmd": "IGN", + "d": "2016-04-03T09:15:43.000Z", + "g": 0, + "h": "", + "id": "20160403091543000|864251020142968|18FA", + "igd": 2567, + "la": 48.733561, + "lo": 37.590581, + "m": 0, + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "cmd": "PFA", + "d": "2016-04-03T09:15:43.000Z", + "id": "20160403091543000|864251020142968|18FB", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "b": true, + "cmd": "PNA", + "d": "2016-04-03T09:15:54.000Z", + "id": "20160403091554000|864251020142968|18FC", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "b": true, + "cmd": "MPN", + "d": "2016-04-03T09:15:56.000Z", + "g": 0, + "id": "20160403091556000|864251020142968|18FD", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "b": true, + "cmd": "OPN", + "d": "2016-04-03T09:15:58.000Z", + "g": 0, + "id": "20160403091558000|864251020142968|18FE", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "b": true, + "cmd": "IGN", + "d": "2016-04-03T09:16:13.000Z", + "g": 0, + "h": "", + "id": "20160403091613000|864251020142968|1900", + "igd": 0, + "m": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 0.9, + "establishment": null, + "googlePlaceId": "EmrQstGD0LvQuNGG0Y8g0K7QstGW0LvQtdC50L3QsCwgMTksINCa0YDQsNC80LDRgtC-0YDRgdGM0LosINCU0L7QvdC10YbRjNC60LAg0L7QsdC70LDRgdGC0YwsINCj0LrRgNCw0ZfQvdCw", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 19, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7273668, + "longitude": 37.5957526, + "streetName": "Yuvileina Street", + "streetNumber": "19" + }, + "b": true, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:16:22.000Z", + "g": 3, + "h": "", + "id": "20160403091622000|864251020142968|1902", + "ig": true, + "la": 48.727476, + "lo": 37.595394, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 1, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 0, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJzYrqPPmW30AR5LCV59s812Q", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Parkova St, 79, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.728186, + "longitude": 37.59508599999999, + "streetName": "Parkova Street", + "streetNumber": "79" + }, + "cmd": "OBD", + "d": "2016-04-03T09:16:27.000Z", + "g": 0, + "id": "20160403091627000|864251020142968|1903", + "la": 48.727529, + "lo": 37.595375, + "m": 0, + "obd": { + "RPMs": 919, + "connect": true, + "diagnosticTroubleCodes": [], + "diagnosticTroubleCodesCount": 1, + "engineLoad": 38, + "malfunction": false, + "malfunctionActivatedDistance": 244, + "mileage": 0, + "powermV": 13680, + "speed": 17, + "supportPIDs": "981B81C0", + "temp": 220, + "throttlePosition": 18, + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 1.5, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 95, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJzYrqPPmW30AR5LCV59s812Q", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Parkova St, 79, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.728186, + "longitude": 37.59508599999999, + "streetName": "Parkova Street", + "streetNumber": "79" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:16:45.000Z", + "g": 3, + "h": "", + "id": "20160403091645000|864251020142968|1906", + "ig": true, + "la": 48.72759, + "lo": 37.595857, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 9, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 35, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJzYrqPPmW30AR5LCV59s812Q", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Parkova St, 79, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.728186, + "longitude": 37.59508599999999, + "streetName": "Parkova Street", + "streetNumber": "79" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:16:51.000Z", + "g": 3, + "h": "", + "id": "20160403091651000|864251020142968|1909", + "ig": true, + "la": 48.727687, + "lo": 37.59602, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "1", + "s": 11.3, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:18:21.000Z", + "g": 1, + "h": "", + "id": "20160403091821000|864251020142968|190B", + "ig": true, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "cmd": "JES", + "d": "2016-04-03T09:18:25.000Z", + "id": "20160403091825000|864251020142968|190C", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "cmd": "IGF", + "d": "2016-04-03T09:18:25.000Z", + "g": 0, + "h": "", + "id": "20160403091825000|864251020142968|190D", + "igd": 131, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T09:18:27.000Z", + "g": 0, + "id": "20160403091827000|864251020142968|190E", + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 13069, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:18:29.000Z", + "g": 1, + "h": "", + "id": "20160403091829000|864251020142968|1910", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": true, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:23:59.000Z", + "g": 1, + "h": "", + "id": "20160403092359000|864251020142968|1912", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T09:28:25.000Z", + "g": 0, + "id": "20160403092825000|864251020142968|1914", + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12844, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:28:58.000Z", + "g": 1, + "h": "", + "id": "20160403092858000|864251020142968|1915", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:33:57.000Z", + "g": 1, + "h": "", + "id": "20160403093357000|864251020142968|1917", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T09:38:23.000Z", + "g": 0, + "id": "20160403093823000|864251020142968|1919", + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12792, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:38:57.000Z", + "g": 1, + "h": "", + "id": "20160403093857000|864251020142968|191A", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:43:56.000Z", + "g": 1, + "h": "", + "id": "20160403094356000|864251020142968|191C", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T09:48:22.000Z", + "g": 0, + "id": "20160403094822000|864251020142968|191E", + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12732, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:48:55.000Z", + "g": 1, + "h": "", + "id": "20160403094855000|864251020142968|191F", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:53:55.000Z", + "g": 1, + "h": "", + "id": "20160403095355000|864251020142968|1921", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "cmd": "OBD", + "d": "2016-04-03T09:58:20.000Z", + "g": 0, + "id": "20160403095820000|864251020142968|1923", + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12701, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T09:58:54.000Z", + "g": 1, + "h": "", + "id": "20160403095854000|864251020142968|1924", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJ4SpxXPmW30ARBXFVJYIJJCE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "Yuvileina St, 54, Kramators'k, Donetsk Oblast, Ukraine, 84300", + "latitude": 48.72922759999999, + "longitude": 37.5965573, + "streetName": "Yuvileina Street", + "streetNumber": "54", + "zipcode": "84300" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:03:53.000Z", + "faketow": true, + "g": 1, + "h": "", + "id": "20160403100353000|864251020142968|1926", + "ig": false, + "la": 48.728947, + "lo": 37.597253, + "m": 0, + "p": "", + "rid": "1", + "rty": "0", + "s": 17.3, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T10:08:18.000Z", + "g": 0, + "id": "20160403100818000|864251020142968|1928", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12972, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:08:53.000Z", + "g": 1, + "h": "", + "id": "20160403100853000|864251020142968|1929", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:13:52.000Z", + "g": 1, + "h": "", + "id": "20160403101352000|864251020142968|192B", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T10:18:16.000Z", + "g": 0, + "id": "20160403101816000|864251020142968|192E", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12884, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:18:51.000Z", + "g": 1, + "h": "", + "id": "20160403101851000|864251020142968|192F", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:23:51.000Z", + "g": 1, + "h": "", + "id": "20160403102351000|864251020142968|1931", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T10:28:14.000Z", + "g": 0, + "id": "20160403102814000|864251020142968|1933", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12852, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:28:50.000Z", + "g": 1, + "h": "", + "id": "20160403102850000|864251020142968|1934", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:33:49.000Z", + "g": 1, + "h": "", + "id": "20160403103349000|864251020142968|1936", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T10:38:12.000Z", + "g": 0, + "id": "20160403103812000|864251020142968|1938", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12820, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:38:49.000Z", + "g": 1, + "h": "", + "id": "20160403103849000|864251020142968|1939", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:43:48.000Z", + "g": 1, + "h": "", + "id": "20160403104348000|864251020142968|193B", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T10:48:10.000Z", + "g": 0, + "id": "20160403104810000|864251020142968|193D", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12792, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:48:47.000Z", + "g": 1, + "h": "", + "id": "20160403104847000|864251020142968|193E", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:53:47.000Z", + "g": 1, + "h": "", + "id": "20160403105347000|864251020142968|1940", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T10:58:09.000Z", + "g": 0, + "id": "20160403105809000|864251020142968|1942", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12787, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T10:58:46.000Z", + "g": 1, + "h": "", + "id": "20160403105846000|864251020142968|1943", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:03:45.000Z", + "g": 1, + "h": "", + "id": "20160403110345000|864251020142968|1945", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T11:08:07.000Z", + "g": 0, + "id": "20160403110807000|864251020142968|1947", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12763, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:08:45.000Z", + "g": 1, + "h": "", + "id": "20160403110845000|864251020142968|1948", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:13:44.000Z", + "g": 1, + "h": "", + "id": "20160403111344000|864251020142968|194A", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T11:18:05.000Z", + "g": 0, + "id": "20160403111805000|864251020142968|194D", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12736, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:18:43.000Z", + "g": 1, + "h": "", + "id": "20160403111843000|864251020142968|194E", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:23:43.000Z", + "g": 1, + "h": "", + "id": "20160403112343000|864251020142968|1950", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T11:28:03.000Z", + "g": 0, + "id": "20160403112803000|864251020142968|1952", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12730, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:28:42.000Z", + "g": 1, + "h": "", + "id": "20160403112842000|864251020142968|1953", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:33:41.000Z", + "g": 1, + "h": "", + "id": "20160403113341000|864251020142968|1955", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T11:38:01.000Z", + "g": 0, + "id": "20160403113801000|864251020142968|1957", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12564, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:38:40.000Z", + "g": 1, + "h": "", + "id": "20160403113840000|864251020142968|1958", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:43:40.000Z", + "g": 0, + "h": "", + "id": "20160403114340000|864251020142968|195A", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T11:47:59.000Z", + "g": 0, + "id": "20160403114759000|864251020142968|195B", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12642, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:48:39.000Z", + "g": 0, + "h": "", + "id": "20160403114839000|864251020142968|195D", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:53:38.000Z", + "g": 0, + "h": "", + "id": "20160403115338000|864251020142968|195F", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T11:57:58.000Z", + "g": 0, + "id": "20160403115758000|864251020142968|1960", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12643, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T11:58:38.000Z", + "g": 0, + "h": "", + "id": "20160403115838000|864251020142968|1962", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:03:37.000Z", + "g": 0, + "h": "", + "id": "20160403120337000|864251020142968|1964", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T12:07:56.000Z", + "g": 0, + "id": "20160403120756000|864251020142968|1966", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12694, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:08:36.000Z", + "g": 0, + "h": "", + "id": "20160403120836000|864251020142968|1968", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:13:36.000Z", + "g": 0, + "h": "", + "id": "20160403121336000|864251020142968|196B", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T12:17:54.000Z", + "g": 0, + "id": "20160403121754000|864251020142968|196C", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12612, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:18:35.000Z", + "g": 0, + "h": "", + "id": "20160403121835000|864251020142968|196E", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:23:34.000Z", + "g": 0, + "h": "", + "id": "20160403122334000|864251020142968|1970", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T12:27:52.000Z", + "g": 0, + "id": "20160403122752000|864251020142968|1971", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12615, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:28:34.000Z", + "g": 0, + "h": "", + "id": "20160403122834000|864251020142968|1973", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:33:33.000Z", + "g": 0, + "h": "", + "id": "20160403123333000|864251020142968|1975", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T12:37:50.000Z", + "g": 0, + "id": "20160403123750000|864251020142968|1976", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12609, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:38:32.000Z", + "g": 0, + "h": "", + "id": "20160403123832000|864251020142968|1978", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:43:32.000Z", + "g": 0, + "h": "", + "id": "20160403124332000|864251020142968|197A", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T12:47:48.000Z", + "g": 0, + "id": "20160403124748000|864251020142968|197C", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12599, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:48:31.000Z", + "g": 0, + "h": "", + "id": "20160403124831000|864251020142968|197E", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:53:30.000Z", + "g": 0, + "h": "", + "id": "20160403125330000|864251020142968|1980", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T12:57:46.000Z", + "g": 0, + "id": "20160403125746000|864251020142968|1981", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12587, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T12:58:30.000Z", + "g": 0, + "h": "", + "id": "20160403125830000|864251020142968|1983", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:03:29.000Z", + "g": 0, + "h": "", + "id": "20160403130329000|864251020142968|1985", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T13:07:45.000Z", + "g": 0, + "id": "20160403130745000|864251020142968|1986", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12586, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:08:28.000Z", + "g": 0, + "h": "", + "id": "20160403130828000|864251020142968|1988", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:13:28.000Z", + "g": 0, + "h": "", + "id": "20160403131328000|864251020142968|198A", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T13:17:43.000Z", + "g": 0, + "id": "20160403131743000|864251020142968|198B", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12585, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:18:27.000Z", + "g": 0, + "h": "", + "id": "20160403131827000|864251020142968|198D", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:23:26.000Z", + "g": 0, + "h": "", + "id": "20160403132326000|864251020142968|198F", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T13:27:41.000Z", + "g": 0, + "id": "20160403132741000|864251020142968|1990", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12586, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:28:26.000Z", + "g": 0, + "h": "", + "id": "20160403132826000|864251020142968|1992", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:33:25.000Z", + "g": 0, + "h": "", + "id": "20160403133325000|864251020142968|1994", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T13:37:39.000Z", + "g": 0, + "id": "20160403133739000|864251020142968|1995", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12582, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:38:24.000Z", + "g": 0, + "h": "", + "id": "20160403133824000|864251020142968|1997", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:43:23.000Z", + "g": 0, + "h": "", + "id": "20160403134323000|864251020142968|1999", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T13:47:37.000Z", + "g": 0, + "id": "20160403134737000|864251020142968|199B", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12586, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:48:23.000Z", + "g": 0, + "h": "", + "id": "20160403134823000|864251020142968|199D", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:53:22.000Z", + "g": 0, + "h": "", + "id": "20160403135322000|864251020142968|199F", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T13:57:35.000Z", + "g": 0, + "id": "20160403135735000|864251020142968|19A0", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12586, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T13:58:21.000Z", + "g": 0, + "h": "", + "id": "20160403135821000|864251020142968|19A2", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:03:21.000Z", + "g": 0, + "h": "", + "id": "20160403140321000|864251020142968|19A4", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T14:07:34.000Z", + "g": 0, + "id": "20160403140734000|864251020142968|19A5", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12585, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:08:20.000Z", + "g": 0, + "h": "", + "id": "20160403140820000|864251020142968|19A7", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:13:19.000Z", + "g": 0, + "h": "", + "id": "20160403141319000|864251020142968|19A9", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T14:17:32.000Z", + "g": 0, + "id": "20160403141732000|864251020142968|19AB", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12587, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:18:19.000Z", + "g": 0, + "h": "", + "id": "20160403141819000|864251020142968|19AD", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:23:18.000Z", + "g": 0, + "h": "", + "id": "20160403142318000|864251020142968|19AF", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T14:27:30.000Z", + "g": 0, + "id": "20160403142730000|864251020142968|19B0", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12585, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:28:17.000Z", + "g": 0, + "h": "", + "id": "20160403142817000|864251020142968|19B2", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:33:17.000Z", + "g": 0, + "h": "", + "id": "20160403143317000|864251020142968|19B4", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T14:37:28.000Z", + "g": 0, + "id": "20160403143728000|864251020142968|19B5", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12582, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:38:16.000Z", + "g": 0, + "h": "", + "id": "20160403143816000|864251020142968|19B7", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:43:15.000Z", + "g": 0, + "h": "", + "id": "20160403144315000|864251020142968|19B9", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T14:47:26.000Z", + "g": 0, + "id": "20160403144726000|864251020142968|19BA", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12584, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:48:14.000Z", + "g": 0, + "h": "", + "id": "20160403144814000|864251020142968|19BC", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:53:14.000Z", + "g": 0, + "h": "", + "id": "20160403145314000|864251020142968|19BE", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T14:57:24.000Z", + "g": 0, + "id": "20160403145724000|864251020142968|19BF", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12586, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T14:58:13.000Z", + "g": 0, + "h": "", + "id": "20160403145813000|864251020142968|19C1", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T15:03:12.000Z", + "g": 0, + "h": "", + "id": "20160403150312000|864251020142968|19C3", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T15:07:22.000Z", + "g": 0, + "id": "20160403150722000|864251020142968|19C4", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12577, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T15:08:12.000Z", + "g": 0, + "h": "", + "id": "20160403150812000|864251020142968|19C6", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T15:13:11.000Z", + "g": 0, + "h": "", + "id": "20160403151311000|864251020142968|19C8", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T15:17:21.000Z", + "g": 0, + "id": "20160403151721000|864251020142968|19CA", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12579, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T15:18:10.000Z", + "g": 0, + "h": "", + "id": "20160403151810000|864251020142968|19CC", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T15:23:10.000Z", + "g": 0, + "h": "", + "id": "20160403152310000|864251020142968|19CE", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T15:27:19.000Z", + "g": 0, + "id": "20160403152719000|864251020142968|19CF", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12563, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T15:28:09.000Z", + "g": 0, + "h": "", + "id": "20160403152809000|864251020142968|19D1", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T15:33:08.000Z", + "g": 0, + "h": "", + "id": "20160403153308000|864251020142968|19D3", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T15:37:17.000Z", + "g": 0, + "id": "20160403153717000|864251020142968|19D4", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12558, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T15:38:08.000Z", + "g": 0, + "h": "", + "id": "20160403153808000|864251020142968|19D6", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "bp": 100, + "cmd": "FRI", + "d": "2016-04-03T15:43:07.000Z", + "g": 0, + "h": "", + "id": "20160403154307000|864251020142968|19D8", + "ig": false, + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "mo": false, + "p": "", + "rid": "1", + "rty": "0", + "s": 0, + "v": "", + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + }, + { + "a": 56, + "ad": { + "administrativeLevels": { + "level1long": "Donetsk Oblast", + "level1short": "Donetsk Oblast", + "level3long": "Kramators'ka city council", + "level3short": "Kramators'ka city council" + }, + "city": "Kramators'k", + "country": "Ukraine", + "countryCode": "UA", + "extra": { + "confidence": 1, + "establishment": null, + "googlePlaceId": "ChIJV2Ic-U2W30AR7JiSd4DHhkE", + "neighborhood": null, + "premise": null, + "subpremise": null + }, + "formattedAddress": "вулиця Шекспіра, 72, Kramators'k, Donetsk Oblast, Ukraine", + "latitude": 48.7193319, + "longitude": 37.5777603, + "streetName": "вулиця Шекспіра", + "streetNumber": "72" + }, + "cmd": "OBD", + "d": "2016-04-03T15:47:15.000Z", + "g": 0, + "id": "20160403154715000|864251020142968|19D9", + "la": 48.719403, + "lo": 37.577894, + "m": 0, + "obd": { + "connect": true, + "diagnosticTroubleCodes": [], + "malfunction": false, + "powermV": 12556, + "supportPIDs": "981B81C0", + "vin": "JTJHT00W574027368" + }, + "rty": "0", + "s": 0, + "vid": "0c06a8aa-b52f-49b4-8fd1-192b7582f76f", + "vin": "" + } +] diff --git a/src/test/reports/idletest.js b/src/test/reports/idletest.js new file mode 100644 index 0000000..1932309 --- /dev/null +++ b/src/test/reports/idletest.js @@ -0,0 +1,20 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import _ from 'lodash'; +import idleReport from '../../server/lib/reports/idle'; + +test('', function (t) { + t.plan(6); + + const history = require('./apr3.json'); + const totals = Object.create(null); + const result = idleReport(history, totals); + + t.equal(result.totals, 250000, 'total'); + t.equal(result.results.length, 4, '4 idle periods'); + t.equal(result.results[0].idleTime, 96000, 'first idle duration'); + t.equal(result.results[1].idleTime, 55000, 'second idle duration'); + t.equal(result.results[2].idleTime, 9000, 'third idle duration'); + t.equal(result.results[3].idleTime, 90000, 'fourth idle duration'); +}) diff --git a/src/test/reversegeotest.js b/src/test/reversegeotest.js new file mode 100644 index 0000000..95c90a1 --- /dev/null +++ b/src/test/reversegeotest.js @@ -0,0 +1,41 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import reversegeo from '../helper/reversegeo'; +import Promise from 'bluebird'; + +test('reverse geocode', function(t) { + t.plan(3); + + reversegeo(48.667374, 37.538473) + .then(function(result) { + console.log(JSON.stringify(result, null, 4)); + + // + // { + // "administrativeLevels": { + // "level1long": "Donetsk Oblast", + // "level1short": "Donetsk Oblast" + // }, + // "country": "Ukraine", + // "countryCode": "UA", + // "extra": { + // "confidence": 0.7, + // "establishment": null, + // "googlePlaceId": "ChIJ15Y2isa930ARblaFX3jDffM", + // "neighborhood": null, + // "premise": null, + // "subpremise": null + // }, + // "formattedAddress": "H20, Donetsk Oblast, Ukraine", + // "latitude": 48.6674589, + // "longitude": 37.538869, + // "streetName": "H20" + // } + + t.equal(result.formattedAddress, 'H20, Donetsk Oblast, Ukraine'); + t.equal(result.streetName, 'H20'); + t.equal(result.country, 'Ukraine'); + + }) +}) diff --git a/src/test/tractorobd.js b/src/test/tractorobd.js new file mode 100644 index 0000000..930809d --- /dev/null +++ b/src/test/tractorobd.js @@ -0,0 +1,42 @@ +/* Copyright (c) 2016 Grant Miner */ +'use strict'; +import test from 'tape'; +import _ from 'lodash'; +import parse from '../helper/eventreportparser'; +import decimalToHex from '../listen/decimaltohex'; + +test('Tractor OBD', function (t) { + // const x = '+RESP:GTOBD,360100,864251020143040,3LNHL2GC4BR773283,g5,0,79FFFF,3LNHL2GC4BR773283,1,14312,981B81E0,1333,0,8,,65535,0,0,0,,17,49,58,6,40976,0,0.0,0,288.9,-93.399623,44.940529,20160327232242,0310,0260,74B1,9D83,00,278.8,20160327232512,0731$'; + const x = '+RESP:GTOBD,360303,864251020143636,,gv500,0,79FFFF,,1,13696,,1800,,82,,,,,,,,29,,A,1,0,15.7,258,116.0,32.727395,50.515312,20160817045847,,,,,,102.4,20160817045849,0909$'; + const parsed = parse(x); + t.plan(8); + t.equal(parsed.imei, '864251020143636', 'imei') + t.equal(parsed.name, 'gv500', 'name'); + t.equal(parsed.rty, '0', 'report type'); + t.equal(parsed.reportMask, parseInt('79FFFF', 16), 'report mask'); + t.equal(parsed.obd.vin, '', 'obd vin'); + // t.equal(parsed.obd.connect, true, 'odb connect'); + // t.equal(parsed.obd.powermV, 14312, 'odb powermV'); + // t.equal(parsed.obd.supportPIDs, '981B81E0', 'support pids'); + // t.equal(parsed.obd.RPMs, 1333, 'RPMs'); + // t.equal(parsed.obd.speed, 15.7, 'OBD speed'); + // t.equal(parsed.obd.temp, 8, 'OBD temp'); + // t.ok(_.isNaN(parsed.obd.fuelConsumption), 'OBD fuel consumption'); + // t.equal(parsed.obd.DTCsClearedDistanceOverVehicleTotalMileage, 65535, 'OBD DTCsClearedDistanceOverVehicleTotalMileage'); + // t.equal(parsed.obd.malfunctionActivatedDistance, 0, 'OBD malfunctionActivatedDistance'); + // t.equal(parsed.obd.malfunction, false, 'OBD malfunction'); + // t.equal(parsed.obd.diagnosticTroubleCodesCount, 0, 'OBD diagnosticTroubleCodesCount'); + // t.equal(parsed.obd.diagnosticTroubleCodes.length,0 , 'OBD diagnosticTroubleCode length 0'); + // t.equal(parsed.obd.throttlePosition, 17, 'OBD throttlePosition'); + t.equal(parsed.obd.engineLoad, 29, 'engine load'); + // t.equal(parsed.obd.fuelLevelInput, 58, 'fuel level input'); + t.equal(parsed.mileage, 102.4, 'mileage'); + // t.equal(parsed.accuracy, 0, 'accuracy'); + // t.equal(parsed.speed, 0, 'speed'); + // t.equal(parsed.azimuth, 0, 'azimuth'); + // t.equal(parsed.altitude, 288.9, 'altitude'); + // t.equal(parsed.longitude, -93.399623, 'long'); + // t.equal(parsed.latitude, 44.940529, 'lat'); + // t.equal(parsed.mileage, 278.8, 'mileage'); + t.equal(decimalToHex(parsed.count, 4), '0909', 'count'); +}) diff --git a/src/tools/createAnAdmin.js b/src/tools/createAnAdmin.js new file mode 100644 index 0000000..254d232 --- /dev/null +++ b/src/tools/createAnAdmin.js @@ -0,0 +1,49 @@ +/* Copyright (c) 2016 Grant Miner */ + +// Create or update an admin user wih username and password. +// Usage: node createAnAdmin.js username password [rounds] +// Rounds is number of bcrypt hash rounds to perform, e.g. 10. + +'use strict'; +const Promise = require('bluebird'); +const bcrypt = Promise.promisifyAll(require('bcrypt')); +const r = require('../common/db'); +Promise.coroutine(function* () { + let rounds = 10; + if (process.argv[4]) { + rounds = parseInt(process.argv[4]); + } + let salt = yield bcrypt.genSaltAsync(rounds); + let hashedPassword = yield bcrypt.hashAsync(process.argv[3], salt); + + let username = process.argv[2]; + + let existingUser = yield r.table('users').get(username); + + let newUser = { + username: process.argv[2], + password: hashedPassword, + isAdmin: true, + orgid: 'default', + + type: '', + email: '', + firstname: '', + lastname: '', + workphone: '', + mobilephone: '', + fax: '', + timezone: '', + isOrgAdmin: false + } + + let toInsert = Object.assign({}, existingUser, newUser); + + if (existingUser == null) { + yield r.table('users').insert(toInsert); + } else { + yield r.table('users').update(toInsert); + } + + r.getPoolMaster().drain(); // drain pool to allow process to exit. +})(); diff --git a/src/tools/faker.js b/src/tools/faker.js new file mode 100644 index 0000000..7168999 --- /dev/null +++ b/src/tools/faker.js @@ -0,0 +1,74 @@ +/* Copyright (c) 2016 Grant Miner */ + +// Load event data from a file and send as if it came from GPS units. +// Usage: node faker.js filename +// file will be messages separated by newlines. +'use strict'; + +const Promise = require('bluebird'); +const fs = Promise.promisifyAll(require('fs')); +const _ = require('lodash'); +const dgram = Promise.promisifyAll(require('dgram')); + +const config = require('../../config/faker.js'); +const delay = config.delay; + +let filename; +if (process.argv[2]) { + filename = process.argv[2]; +} else { + console.error('Need a filename'); + process.exit(1); +} + +let maxSend; +if (process.argv[3]) { + maxSend = parseInt(process.argv[3], 10); +} else { + maxSend = Infinity; +} + +const port = config.port; +const host = config.host; + +const socket = dgram.createSocket('udp4'); + +socket.on('message', function(msg, rinfo) { + console.log('Received %s from %s:%d', msg, rinfo.address, rinfo.port); +}); + +// Returns a random integer between min (included) and max (included) +// Using Math.round() will give you a non-uniform distribution! +function getRandomIntInclusive(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +Promise.coroutine(function*() { + const data = yield fs.readFileAsync(filename); + messages = data.toString().split(/\r?\n|\r/); + let i = -1; + + while (i < messages.length && i < maxSend) { + i++; + + if (!messages[i]) { + console.log('Message ' + i + ' was null'); + continue; // handle null messages + } else { + // console.log(i); + } + + let message = new Buffer(messages[i]); + // console.log(message.toString()); + if (delay != 0) { + yield Promise.delay(delay) + } + yield socket.sendAsync(message, 0, message.length, port, host); + + if (i === maxSend) { + console.log('Hit max send of ' + maxSend); + } else if (i === messages.length - 1) { + console.log('Sent all ' + messages.length + ' messages'); + } + } +})(); diff --git a/src/tools/filter.js b/src/tools/filter.js new file mode 100644 index 0000000..7834786 --- /dev/null +++ b/src/tools/filter.js @@ -0,0 +1,44 @@ +/* Copyright (c) 2016 Grant Miner */ + +// Load event data from a file and filter by IMEI +// Usage: node filter.js filename imei +'use strict'; + +const Promise = require('bluebird'); +const fs = Promise.promisifyAll(require('fs')); +const _ = require('lodash'); +const parse = require('../helper/eventreportparser'); + +if (process.argv[2]) { + const filename = process.argv[2]; +} else { + console.error('Need a filename'); + process.exit(1); +} + +if (process.argv[3]) { + const imei = process.argv[3]; +} else { + console.error('Need an IMEI'); + process.exit(1); +} + +fs.readFileAsync(filename) +.then(function (data) { + messages = data.toString().split(/\r?\n|\r/); + messages.map(function (message) { + try { + message = message.toString().trim(); + + const parsed = parse(message); + + if (parsed.imei === imei) { + console.log(message); + } + } catch (e) { + console.error('Bad message: ' + message); + console.error(e.stack); + } + }) + +}) diff --git a/src/tools/hash.js b/src/tools/hash.js new file mode 100644 index 0000000..0ba03c7 --- /dev/null +++ b/src/tools/hash.js @@ -0,0 +1,16 @@ +// Hash a password. +// Usage: node hash.js password [rounds] +'use strict'; + +const Promise = require('bluebird'); +const bcrypt = Promise.promisifyAll(require('bcrypt')); + +Promise.coroutine(function* (username) { + let rounds = 10; + if (process.argv[3]) { + rounds = parseInt(process.argv[3]); + } + let salt = yield bcrypt.genSaltAsync(rounds); + let hashedPassword = yield bcrypt.hashAsync(process.argv[2], salt); + console.log(hashedPassword); +})(); diff --git a/src/tools/locgenerator.js b/src/tools/locgenerator.js new file mode 100644 index 0000000..44c553f --- /dev/null +++ b/src/tools/locgenerator.js @@ -0,0 +1,79 @@ +/* Copyright (c) 2016 Grant Miner */ + +// Location fake generator +// e.g., node locgenerator.js 861074021378065 2000 +// Usage: node locgenerator.js imei interval + +'use strict'; + +const Promise = require('bluebird'); +const co = Promise.coroutine; +const fs = Promise.promisifyAll(require('fs')); +const _ = require('lodash'); +const dgram = Promise.promisifyAll(require('dgram')); +const moment = require('moment'); +const config = require('../../config/faker.js'); +const lucidlocation = require('lucidlocation'); +const decimalToHex = require('../listen/decimaltohex'); + +let imei; +if (process.argv[2]) { + imei = process.argv[2]; +} else { + console.error('Need a imei'); + process.exit(1); +} + +let delay; +if (process.argv[3]) { + delay = parseInt(process.argv[3], 10); +} else { + delay = 5000; +} + +const port = config.port; +const host = config.host; + +const socket = dgram.createSocket('udp4'); + +socket.on('message', function(msg, rinfo) { + console.log('Received %s from %s:%d', msg, rinfo.address, rinfo.port); +}); + +// Returns a random integer between min (included) and max (included) +// Using Math.round() will give you a non-uniform distribution! +function getRandomIntInclusive(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +(async function() { + let count = -1; + while (true) { + count++; + if (count > 65535) { + count = 0; + } + let d = moment.utc().format("YYYYMMDDHHmmss"); + console.log(d); + let azimuth = getRandomIntInclusive(0, 360); + let speed = getRandomIntInclusive(0, 100); + let gpsAccuracy = getRandomIntInclusive(0, 20); + let powervcc = 14055; + let randomLocation = lucidlocation.getRandomLocation(); + // let longitude = -82.972203; + let longitude = randomLocation.longitude; + // let latitude = 41.372237; + let latitude = randomLocation.latitude; + let batteryPercent = getRandomIntInclusive(0, 100); + let status = '220100'; + let countH = decimalToHex(count, 4); + + let message = `+RESP:GTFRI,060502,${imei},,${powervcc},10,1,${gpsAccuracy},${speed},${azimuth},,${longitude},${latitude},${d},,,,,,0,FAKE:00:00,,,${batteryPercent},${status},,,,${d},${countH}$` + console.log(message); + + await socket.sendAsync(message, 0, message.length, port, host); + if (delay != 0) { + await Promise.delay(delay) + } + } +})(); diff --git a/src/tools/redb.js b/src/tools/redb.js new file mode 100644 index 0000000..dfd1c48 --- /dev/null +++ b/src/tools/redb.js @@ -0,0 +1,50 @@ +/* Copyright (c) 2016 Grant Miner */ + +'use strict'; +// Dangerous !!! +// Drops and recreates the vehicles/vehiclehistory tables for development. + +const Promise = require('bluebird'); +const r = require('../common/db'); +const os = require('os'); + +function ignore(e) { + console.error(e); + return undefined; +} + +const hostname = os.hostname(); + +let inquirer = require("inquirer"); +inquirer.prompt([{ + type: "expand", + message: "You sure you want to drop the vehicle and vehiclehistory tables?? On " + hostname + "?", + name: "deleteTables", + choices: [{ + key: "n", + name: "No", + value: "no" + }, { + key: "y", + name: "Yes", + value: "yes" + }, + new inquirer.Separator(), { + key: "x", + name: "Abort", + value: "abort" + } + ] + }], + function(answers) { + if (answers.deleteTables === 'yes') { + Promise.coroutine(function*() { + yield Promise.join(r.tableDrop('vehicles').catch(ignore), r.tableDrop('devices').catch(ignore), r.tableDrop('vehiclehistory').catch(ignore), r.tableDrop('rawevents').catch(ignore)); + console.log('Done. Run Schema next. '); + r.getPoolMaster().drain(); // drain connection pool to allow process to exit. + })(); + } else { + r.getPoolMaster().drain(); // drain connection pool to allow process to exit. + } + } +); diff --git a/src/tools/schema.js b/src/tools/schema.js new file mode 100644 index 0000000..33691b8 --- /dev/null +++ b/src/tools/schema.js @@ -0,0 +1,50 @@ +/* Copyright (c) 2016 Grant Miner */ + +'use strict'; +// Auto creates the DB schema. Safe to run if it already exists. + +const Promise = require('bluebird'); +const r = require('../common/db'); + +function ignore(e) { + return undefined; +} + +Promise.coroutine(function* () { + yield Promise.join( + r.dbCreate('agilegps').catch(ignore) + , r.tableCreate('rawevents').catch(ignore) + , r.tableCreate('users', {primaryKey: 'username'}).catch(ignore) + , r.tableCreate('organizations').catch(ignore) + , r.tableCreate('devices', {primaryKey: 'imei'}).catch(ignore) + , r.tableCreate('vehicles').catch(ignore) + , r.tableCreate('vehiclehistory').catch(ignore) + , r.tableCreate('geocode').catch(ignore) + , r.tableCreate('errors').catch(ignore) + , r.tableCreate('fleets').catch(ignore) + , r.tableCreate('locations').catch(ignore) + , r.tableCreate('alerts').catch(ignore) + ) + + yield Promise.join( + r.table('users').indexCreate('username').catch(ignore) + , r.table('geocode').indexCreate('location').catch(ignore) + , r.table('vehiclehistory').indexCreate('vid').catch(ignore) + , r.table('vehiclehistory').indexCreate('d').catch(ignore) + , r.table('vehicles').indexCreate('device').catch(ignore) + , r.table('vehicles').indexCreate('orgid').catch(ignore) + , r.table('rawevents').indexCreate('date').catch(ignore) + , r.table('rawevents').indexCreate('imei').catch(ignore) + , r.table('events').indexCreate('date').catch(ignore) + , r.table('devices').indexCreate('orgid').catch(ignore) + , r.table('users').indexCreate('orgid').catch(ignore) + , r.table('fleets').indexCreate('orgid').catch(ignore) + , r.table('locations').indexCreate('orgid').catch(ignore) + , r.table('alerts').indexCreate('orgid').catch(ignore) + ) + + , r.table('organizations').insert({'address1':'Default','address2':"","city":"Minneapolis","country":"USA","ein":"default","id":"default","name":"default","state":"MN","zip":"55419"}).catch(ignore); + + console.log('Done.'); + r.getPoolMaster().drain(); // drain connection pool to allow process to exit. +})(); diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..245a262 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,129 @@ +'use strict'; +var webpack = require('webpack'); +var NODE_ENV = process.env.NODE_ENV || null; + +var plugins = []; +plugins.push(new webpack.ProvidePlugin({ + 'Promise': 'bluebird' +})); + + +if (NODE_ENV === 'production') { + plugins.push(new webpack.optimize.UglifyJsPlugin()); + plugins.push(new webpack.DefinePlugin({ + 'process.env.NODE_ENV': '"production"' + })) +} + +plugins.push(new webpack.optimize.CommonsChunkPlugin({ name: 'vendors', filename: 'vendors.js' })); + +module.exports = { + context: __dirname + '/src/client', + node: { + fs: "empty", + tls: "empty", + }, + entry: { + app: './main.js', + vendors: [ + 'bluebird', + 'bootstrap/less/bootstrap.less', + 'cookies-js', + 'events', + 'j2c', + 'lodash', + 'mithril', + 'moment', + 'nprogress', + 'pikaday2', + 'raf', + 'redux', + 'redux-logger', + 'setimmediate', + 'socket.io-client', + 'validator', + 'velocity-animate', + 'windrose', + ] + }, + output: { + path: __dirname + '/public/app', + filename: 'bundle.js' + }, + module: { + // preLoaders: [ + // {test: /\.js$/, exclude: /node_modules/, loader: 'jshint-loader'} + // ], + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: "babel-loader", + query: { + presets: ['es2015'] + } + }, + { + test: /bootstrap\/js\//, + use: { + loader: "imports-loader", + options: { + jQuery: "jquery" + } + } + }, + { + test: /\.less$/, + use: [ + { loader: "style-loader" }, + { loader: "css-loader" }, + { loader: "less-loader" } + ] + }, + { + test: /\.css$/, + use: [ + { loader: "style-loader" }, + { loader: "css-loader" } + ] + }, + { + test: /\.woff(2)?(\?v=\d+\.\d+\.\d+)?$/, + use: { + loader: "url-loader", + options: { + limit: 10000, + mimetype: "application/font-woff" + } + } + }, + { + test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, + use: { + loader: "url-loader", + options: { + limit: 10000, + mimetype: "application/octet-stream" + } + } + }, + { + test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, + use: { + loader: "file-loader" + } + }, + { + test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, + use: { + loader: "url-loader", + options: { + limit: 10000, + mimetype: "image/svg+xml" + } + } + } + ] + }, + plugins: plugins +}; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..7a67074 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,5703 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +abbrev@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +accepts@1.3.3, accepts@^1.2.2, accepts@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +acorn-dynamic-import@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.1.tgz#23f671eb6e650dab277fef477c321b1178a8cca2" + dependencies: + acorn "^4.0.3" + +acorn@^4.0.3, acorn@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + +ajv-keywords@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.0.tgz#c11e6859eafff83e0dafc416929472eca946aa2c" + +ajv@^4.7.0: + version "4.10.4" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.10.4.tgz#c0974dd00b3464984892d6010aa9c2c945933254" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +any-promise@^1.0.0, any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + dependencies: + default-require-extensions "^1.0.0" + +aproba@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arraybuffer.slice@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + +arrify@^1.0.0, arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asap@~2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + +asn1.js@^4.0.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +assign-styles@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assign-styles/-/assign-styles-2.0.0.tgz#952caaf65acf9974cde6ba369047217a029d9493" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async@^1.4.0, async@^1.4.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.0.1, async@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.4.tgz#2d2160c7788032e4dd6cbe2502f1f9a2c8f6cde4" + dependencies: + lodash "^4.14.0" + +async@~0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +autoprefixer@^6.3.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.6.1.tgz#11a4077abb4b313253ec2f6e1adb91ad84253519" + dependencies: + browserslist "~1.5.1" + caniuse-db "^1.0.30000604" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^5.2.8" + postcss-value-parser "^3.2.3" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +babel-cli@^6.0.0, babel-cli@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.18.0.tgz#92117f341add9dead90f6fa7d0a97c0cc08ec186" + dependencies: + babel-core "^6.18.0" + babel-polyfill "^6.16.0" + babel-register "^6.18.0" + babel-runtime "^6.9.0" + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.0.0" + glob "^5.0.5" + lodash "^4.2.0" + output-file-sync "^1.1.0" + path-is-absolute "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + v8flags "^2.0.10" + optionalDependencies: + chokidar "^1.0.0" + +babel-code-frame@^6.11.0, babel-code-frame@^6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.20.0.tgz#b968f839090f9a8bc6d41938fb96cb84f7387b26" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^2.0.0" + +babel-core@^6.18.0, babel-core@^6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.21.0.tgz#75525480c21c803f826ef3867d22c19f080a3724" + dependencies: + babel-code-frame "^6.20.0" + babel-generator "^6.21.0" + babel-helpers "^6.16.0" + babel-messages "^6.8.0" + babel-register "^6.18.0" + babel-runtime "^6.20.0" + babel-template "^6.16.0" + babel-traverse "^6.21.0" + babel-types "^6.21.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-generator@^6.18.0, babel-generator@^6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.21.0.tgz#605f1269c489a1c75deeca7ea16d43d4656c8494" + dependencies: + babel-messages "^6.8.0" + babel-runtime "^6.20.0" + babel-types "^6.21.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + +babel-helper-call-delegate@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.18.0.tgz#05b14aafa430884b034097ef29e9f067ea4133bd" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-define-map@^6.18.0, babel-helper-define-map@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.18.0.tgz#8d6c85dc7fbb4c19be3de40474d18e97c3676ec2" + dependencies: + babel-helper-function-name "^6.18.0" + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-function-name@^6.18.0, babel-helper-function-name@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.18.0.tgz#68ec71aeba1f3e28b2a6f0730190b754a9bf30e6" + dependencies: + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-get-function-arity@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.18.0.tgz#a5b19695fd3f9cdfc328398b47dafcd7094f9f24" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-hoist-variables@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.18.0.tgz#a835b5ab8b46d6de9babefae4d98ea41e866b82a" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-optimise-call-expression@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.18.0.tgz#9261d0299ee1a4f08a6dd28b7b7c777348fd8f0f" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-regex@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.18.0.tgz#ae0ebfd77de86cb2f1af258e2cc20b5fe893ecc6" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-remap-async-to-generator@^6.16.0: + version "6.20.3" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.20.3.tgz#9dd3b396f13e35ef63e538098500adc24c63c4e7" + dependencies: + babel-helper-function-name "^6.18.0" + babel-runtime "^6.20.0" + babel-template "^6.16.0" + babel-traverse "^6.20.0" + babel-types "^6.20.0" + +babel-helper-replace-supers@^6.18.0, babel-helper-replace-supers@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.18.0.tgz#28ec69877be4144dbd64f4cc3a337e89f29a924e" + dependencies: + babel-helper-optimise-call-expression "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helpers@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.16.0.tgz#1095ec10d99279460553e67eb3eee9973d3867e3" + dependencies: + babel-runtime "^6.0.0" + babel-template "^6.16.0" + +babel-loader@^6.2.10: + version "6.2.10" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.10.tgz#adefc2b242320cd5d15e65b31cea0e8b1b02d4b0" + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.11" + mkdirp "^0.5.1" + object-assign "^4.0.1" + +babel-messages@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-check-es2015-constants@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.8.0.tgz#dbf024c32ed37bfda8dee1e76da02386a8d26fe7" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-transform-async-to-generator@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.16.0.tgz#19ec36cb1486b59f9f468adfa42ce13908ca2999" + dependencies: + babel-helper-remap-async-to-generator "^6.16.0" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-async-to-module-method@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-module-method/-/babel-plugin-transform-async-to-module-method-6.16.0.tgz#3c88b4f0c5bf65e7b5960a48731f21ad0fb5a55f" + dependencies: + babel-helper-remap-async-to-generator "^6.16.0" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.0.0" + babel-types "^6.16.0" + +babel-plugin-transform-es2015-arrow-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz#5b63afc3181bdc9a8c4d481b5a4f3f7d7fef3d9d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.8.0.tgz#ed95d629c4b5a71ae29682b998f70d9833eb366d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoping@^6.18.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.21.0.tgz#e840687f922e70fb2c42bb13501838c174a115ed" + dependencies: + babel-runtime "^6.20.0" + babel-template "^6.15.0" + babel-traverse "^6.21.0" + babel-types "^6.21.0" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.18.0.tgz#ffe7a17321bf83e494dcda0ae3fc72df48ffd1d9" + dependencies: + babel-helper-define-map "^6.18.0" + babel-helper-function-name "^6.18.0" + babel-helper-optimise-call-expression "^6.18.0" + babel-helper-replace-supers "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-template "^6.14.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-computed-properties@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.8.0.tgz#f51010fd61b3bd7b6b60a5fdfd307bb7a5279870" + dependencies: + babel-helper-define-map "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-destructuring@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.19.0.tgz#ff1d911c4b3f4cab621bd66702a869acd1900533" + dependencies: + babel-runtime "^6.9.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz#fd8f7f7171fc108cc1c70c3164b9f15a81c25f7d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-for-of@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.18.0.tgz#4c517504db64bf8cfc119a6b8f177211f2028a70" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-function-name@^6.9.0: + version "6.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.9.0.tgz#8c135b17dbd064e5bba56ec511baaee2fca82719" + dependencies: + babel-helper-function-name "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.9.0" + +babel-plugin-transform-es2015-literals@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.8.0.tgz#50aa2e5c7958fc2ab25d74ec117e0cc98f046468" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-modules-amd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.18.0.tgz#49a054cbb762bdf9ae2d8a807076cfade6141e40" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.18.0.tgz#c15ae5bb11b32a0abdcc98a5837baa4ee8d67bcc" + dependencies: + babel-plugin-transform-strict-mode "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.19.0.tgz#50438136eba74527efa00a5b0fefaf1dc4071da6" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.11.6" + babel-template "^6.14.0" + +babel-plugin-transform-es2015-modules-umd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.18.0.tgz#23351770ece5c1f8e83ed67cb1d7992884491e50" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-object-super@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.8.0.tgz#1b858740a5a4400887c23dcff6f4d56eea4a24c5" + dependencies: + babel-helper-replace-supers "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-parameters@^6.18.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.21.0.tgz#46a655e6864ef984091448cdf024d87b60b2a7d8" + dependencies: + babel-helper-call-delegate "^6.18.0" + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.9.0" + babel-template "^6.16.0" + babel-traverse "^6.21.0" + babel-types "^6.21.0" + +babel-plugin-transform-es2015-shorthand-properties@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.18.0.tgz#e2ede3b7df47bf980151926534d1dd0cbea58f43" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-spread@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.8.0.tgz#0217f737e3b821fa5a669f187c6ed59205f05e9c" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-sticky-regex@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.8.0.tgz#e73d300a440a35d5c64f5c2a344dc236e3df47be" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-template-literals@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.8.0.tgz#86eb876d0a2c635da4ec048b4f7de9dfc897e66b" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.18.0.tgz#0b14c48629c90ff47a0650077f6aa699bee35798" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-unicode-regex@^6.3.13: + version "6.11.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz#6298ceabaad88d50a3f4f392d8de997260f6ef2c" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-regenerator@^6.16.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.21.0.tgz#75d0c7e7f84f379358f508451c68a2c5fa5a9703" + dependencies: + regenerator-transform "0.9.8" + +babel-plugin-transform-strict-mode@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.18.0.tgz#df7cf2991fe046f44163dcd110d5ca43bc652b9d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-polyfill@^6.16.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.20.0.tgz#de4a371006139e20990aac0be367d398331204e7" + dependencies: + babel-runtime "^6.20.0" + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-preset-es2015@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.18.0.tgz#b8c70df84ec948c43dcf2bf770e988eb7da88312" + dependencies: + babel-plugin-check-es2015-constants "^6.3.13" + babel-plugin-transform-es2015-arrow-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoped-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoping "^6.18.0" + babel-plugin-transform-es2015-classes "^6.18.0" + babel-plugin-transform-es2015-computed-properties "^6.3.13" + babel-plugin-transform-es2015-destructuring "^6.18.0" + babel-plugin-transform-es2015-duplicate-keys "^6.6.0" + babel-plugin-transform-es2015-for-of "^6.18.0" + babel-plugin-transform-es2015-function-name "^6.9.0" + babel-plugin-transform-es2015-literals "^6.3.13" + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-plugin-transform-es2015-modules-systemjs "^6.18.0" + babel-plugin-transform-es2015-modules-umd "^6.18.0" + babel-plugin-transform-es2015-object-super "^6.3.13" + babel-plugin-transform-es2015-parameters "^6.18.0" + babel-plugin-transform-es2015-shorthand-properties "^6.18.0" + babel-plugin-transform-es2015-spread "^6.3.13" + babel-plugin-transform-es2015-sticky-regex "^6.3.13" + babel-plugin-transform-es2015-template-literals "^6.6.0" + babel-plugin-transform-es2015-typeof-symbol "^6.18.0" + babel-plugin-transform-es2015-unicode-regex "^6.3.13" + babel-plugin-transform-regenerator "^6.16.0" + +babel-register@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68" + dependencies: + babel-core "^6.18.0" + babel-runtime "^6.11.6" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.9.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.20.0.tgz#87300bdcf4cd770f09bf0048c64204e17806d16f" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-tap@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/babel-tap/-/babel-tap-5.0.0.tgz#3a01ee07b083e775a53b95b6f02110f04e3a22bb" + dependencies: + babel-cli "^6.0.0" + tap ">=2.1.0" + +babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.8.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" + dependencies: + babel-runtime "^6.9.0" + babel-traverse "^6.16.0" + babel-types "^6.16.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.20.0, babel-traverse@^6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.21.0.tgz#69c6365804f1a4f69eb1213f85b00a818b8c21ad" + dependencies: + babel-code-frame "^6.20.0" + babel-messages "^6.8.0" + babel-runtime "^6.20.0" + babel-types "^6.21.0" + babylon "^6.11.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.20.0, babel-types@^6.21.0, babel-types@^6.8.0, babel-types@^6.9.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.21.0.tgz#314b92168891ef6d3806b7f7a917fdf87c11a4b2" + dependencies: + babel-runtime "^6.20.0" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0, babylon@^6.13.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + +balanced-match@^0.4.1, balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + +base64-font-loader@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/base64-font-loader/-/base64-font-loader-0.0.4.tgz#344ed6d7e3c4969433641f67bb0daf549320b824" + dependencies: + loader-utils "~0.2.5" + +base64-js@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + +base64-url@1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/base64-url/-/base64-url-1.3.3.tgz#f8b6c537f09a4fc58c99cb86e0b0e9c61461a20f" + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + +base64url@2.0.0, base64url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" + +basic-auth@~1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.0.4.tgz#030935b01de7c9b94a824b29f3fccb750d3a5290" + +bcrypt-pbkdf@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + dependencies: + tweetnacl "^0.14.3" + +bcrypt@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-1.0.2.tgz#d05fc5d223173e0e28ec381c0f00cc25ffaf2736" + dependencies: + bindings "1.2.1" + nan "2.5.0" + node-pre-gyp "0.6.32" + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + dependencies: + callsite "1.0.0" + +big.js@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +binary@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + dependencies: + buffers "~0.1.1" + chainsaw "~0.1.0" + +bindings@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" + +bl@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" + dependencies: + readable-stream "~2.0.5" + +blob@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird-co@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/bluebird-co/-/bluebird-co-2.2.0.tgz#e0a49e63b6b17e34c91f48b3934b769a377fbed7" + +"bluebird@>= 3.0.1", bluebird@^3.1.1, bluebird@^3.3.1, bluebird@^3.4.1, bluebird@^3.4.6, bluebird@^3.4.7: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +bootstrap@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.3.7.tgz#5a389394549f23330875a3b150656574f8a9eb71" + +bowser@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.6.0.tgz#37fc387b616cb6aef370dab4d6bd402b74c5c54d" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +brorand@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.0.6.tgz#4028706b915f91f7b349a2e0bf3c376039d216e5" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a" + dependencies: + buffer-xor "^1.0.2" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + inherits "^2.0.1" + +browserify-cipher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.0.tgz#10773910c3c206d5420a46aad8694f820b85968f" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + +browserslist@^1.0.1, browserslist@^1.5.2, browserslist@~1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.5.2.tgz#1c82fde0ee8693e6d15c49b7bff209dc06298c56" + dependencies: + caniuse-db "^1.0.30000604" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +buffer-xor@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +bunyan@^1.8.5: + version "1.8.5" + resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.5.tgz#0d619e83005fb89070f5f47982fc1bf00600878a" + optionalDependencies: + dtrace-provider "~0.8" + moment "^2.10.6" + mv "~2" + safe-json-stringify "~1" + +bunyan@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.5.1.tgz#5f6e7d44c43b952f56b0f41309e3ab12391b4e2d" + optionalDependencies: + dtrace-provider "~0.6" + mv "~2" + safe-json-stringify "~1" + +bytes@2.4.0, bytes@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + +caching-transform@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-1.0.1.tgz#6dbdb2f20f8d8fbce79f3e94e9d1742dcdf5c0a1" + dependencies: + md5-hex "^1.2.0" + mkdirp "^0.5.1" + write-file-atomic "^1.1.4" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +camelize@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + +caniuse-api@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.5.2.tgz#8f393c682f661c0a997b77bba6e826483fb3600e" + dependencies: + browserslist "^1.0.1" + caniuse-db "^1.0.30000346" + lodash.memoize "^4.1.0" + lodash.uniq "^4.3.0" + shelljs "^0.7.0" + +caniuse-db@^1.0.30000346, caniuse-db@^1.0.30000604: + version "1.0.30000611" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000611.tgz#1075d14d9b3cc153caf5e9e35f45565b03304c37" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + dependencies: + traverse ">=0.3.0 <0.4" + +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^1.0.0, chokidar@^1.4.3: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07" + dependencies: + inherits "^2.0.1" + +clap@^1.0.9: + version "1.1.2" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.2.tgz#316545bf22229225a2cecaa6824cd2f56a9709ed" + dependencies: + chalk "^1.1.3" + +clean-yaml-object@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz#63fb110dc2ce1a84dc21f6d9334876d010ae8b68" + +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +cli@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cli/-/cli-1.0.1.tgz#22817534f24bfa4950c34d532d48ecbc621b8c14" + dependencies: + exit "0.1.2" + glob "^7.1.1" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +clone@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + +co-body@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/co-body/-/co-body-4.2.0.tgz#74df20fa73262125dc45482af04e342ea8db3515" + dependencies: + inflation "~2.0.0" + qs "~4.0.0" + raw-body "~2.1.2" + type-is "~1.6.6" + +co-request@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/co-request/-/co-request-0.2.1.tgz#6428c002ad4229b3eda6725022aeccf273bee3fb" + dependencies: + request "*" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +coa@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3" + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collections@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/collections/-/collections-3.0.0.tgz#27e3894df1b24cedfc55a1bbb0c0da12f68bab31" + dependencies: + weak-map "~1.0.x" + +color-convert@^1.3.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + dependencies: + color-name "^1.1.1" + +color-name@^1.0.0, color-name@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color-support@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.2.tgz#49cc99b89d1bdef1292e9d9323c66971a33eb89d" + +color@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" + dependencies: + clone "^1.0.2" + color-convert "^1.3.0" + color-string "^0.3.0" + +colormin@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" + dependencies: + color "^0.11.0" + css-color-names "0.0.4" + has "^1.0.1" + +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.8.1, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + +component-emitter@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + +compressible@^2.0.0: + version "2.0.9" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" + dependencies: + mime-db ">= 1.24.0 < 2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.7: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +configstore@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" + dependencies: + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + object-assign "^4.0.1" + os-tmpdir "^1.0.0" + osenv "^0.1.0" + uuid "^2.0.1" + write-file-atomic "^1.1.2" + xdg-basedir "^2.0.0" + +connect@3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.4.1.tgz#a21361d3f4099ef761cda6dc4a973bb1ebb0a34d" + dependencies: + debug "~2.2.0" + finalhandler "0.4.1" + parseurl "~1.3.1" + utils-merge "1.0.0" + +console-browserify@1.1.x, console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +content-disposition@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" + +content-disposition@~0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-security-policy-builder@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-1.0.0.tgz#11fd40c5cc298a6c725a35f9acf71e82ab5d3243" + dependencies: + dashify "^0.2.0" + +content-type@^1.0.0, content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +convert-source-map@^1.1.0, convert-source-map@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +cookies-js@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/cookies-js/-/cookies-js-1.2.3.tgz#03315049e7c52bee3f73186a69167eab0ddb2d31" + +cookies@~0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.6.2.tgz#6ac1b052895208e8fc4c4f5f86a9ed31b9cb5ccf" + dependencies: + depd "~1.1.0" + keygrip "~1.0.1" + +copy-to@^2.0.1, copy-to@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/copy-to/-/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5" + +copy@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/copy/-/copy-0.0.1.tgz#e3b014b4171c23a08ebaeca0396813ca22caf572" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +coveralls@^2.11.2: + version "2.11.15" + resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.11.15.tgz#37d3474369d66c14f33fa73a9d25cee6e099fca0" + dependencies: + js-yaml "3.6.1" + lcov-parse "0.0.10" + log-driver "1.2.5" + minimist "1.2.0" + request "2.75.0" + +crc@~3.4.0: + version "3.4.4" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b" + +create-ecdh@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.2.tgz#51210062d7bb7479f6c65bb41a92208b1d61abad" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^1.0.0" + sha.js "^2.3.6" + +create-hmac@^1.1.0, create-hmac@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.4.tgz#d3fb4ba253eb8b3f56e39ea2fbcb8af747bd3170" + dependencies: + create-hash "^1.1.0" + inherits "^2.0.1" + +cross-spawn@^4: + version "4.0.2" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + +css-color-names@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + +css-loader@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.26.1.tgz#2ba7f20131b93597496b3e9bb500785a49cd29ea" + dependencies: + babel-code-frame "^6.11.0" + css-selector-tokenizer "^0.7.0" + cssnano ">=2.6.1 <4" + loader-utils "~0.2.2" + lodash.camelcase "^4.3.0" + object-assign "^4.0.1" + postcss "^5.0.6" + postcss-modules-extract-imports "^1.0.0" + postcss-modules-local-by-default "^1.0.1" + postcss-modules-scope "^1.0.0" + postcss-modules-values "^1.1.0" + source-list-map "^0.1.4" + +css-selector-tokenizer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.6.0.tgz#6445f582c7930d241dcc5007a43d6fcb8f073152" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +css-selector-tokenizer@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + +"cssnano@>=2.6.1 <4": + version "3.10.0" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" + dependencies: + autoprefixer "^6.3.1" + decamelize "^1.1.2" + defined "^1.0.0" + has "^1.0.1" + object-assign "^4.0.1" + postcss "^5.0.14" + postcss-calc "^5.2.0" + postcss-colormin "^2.1.8" + postcss-convert-values "^2.3.4" + postcss-discard-comments "^2.0.4" + postcss-discard-duplicates "^2.0.1" + postcss-discard-empty "^2.0.1" + postcss-discard-overridden "^0.1.1" + postcss-discard-unused "^2.2.1" + postcss-filter-plugins "^2.0.0" + postcss-merge-idents "^2.1.5" + postcss-merge-longhand "^2.0.1" + postcss-merge-rules "^2.0.3" + postcss-minify-font-values "^1.0.2" + postcss-minify-gradients "^1.0.1" + postcss-minify-params "^1.0.4" + postcss-minify-selectors "^2.0.4" + postcss-normalize-charset "^1.1.0" + postcss-normalize-url "^3.0.7" + postcss-ordered-values "^2.1.0" + postcss-reduce-idents "^2.2.2" + postcss-reduce-initial "^1.0.0" + postcss-reduce-transforms "^1.0.3" + postcss-svgo "^2.1.1" + postcss-unique-selectors "^2.0.2" + postcss-value-parser "^3.2.3" + postcss-zindex "^2.0.1" + +csso@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.2.1.tgz#51fbb5347e50e81e6ed51668a48490ae6fe2afe2" + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +dashify@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dashify/-/dashify-0.2.2.tgz#6a07415a01c91faf4a32e38d9dfba71f61cb20fe" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug-log@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" + +debug@*, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" + dependencies: + ms "0.7.2" + +debug@2.2.0, debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + dependencies: + ms "0.7.2" + +decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-diff@0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.4.tgz#aac5c39952236abe5f037a2349060ba01b00ae48" + +deep-equal@^1.0.0, deep-equal@~1.0.0, deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +deep-freeze@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84" + +deeper@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/deeper/-/deeper-2.1.0.tgz#bc564e5f73174fdf201e08b00030e8a14da74368" + +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + dependencies: + strip-bom "^2.0.0" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +defined@^1.0.0, defined@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@1.1.0, depd@^1.1.0, depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@^1.0.3, destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +diff@^1.3.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + +diffie-hellman@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dns-prefetch-control@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +domain-browser@^1.1.1: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +domelementtype@1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" + dependencies: + domelementtype "1" + +domutils@1.5: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +dont-sniff-mimetype@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58" + +dtrace-provider@~0.6: + version "0.6.0" + resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.6.0.tgz#0b078d5517937d873101452d9146737557b75e51" + dependencies: + nan "^2.0.8" + +dtrace-provider@~0.8: + version "0.8.0" + resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.0.tgz#fa95fbf67ed3ae3e97364f9664af7302e5ff5625" + dependencies: + nan "^2.3.3" + +duplexer@~0.0.3: + version "0.0.4" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.0.4.tgz#afcb7f1f8b8d74f820726171d5d64ac9e4a8ff20" + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +duplexify@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.0.tgz#1aa773002e1578457e9d9d4a50b0ccaaebcbd604" + dependencies: + end-of-stream "1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ecdsa-sig-formatter@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz#4bc926274ec3b5abb5016e7e1d60921ac262b2a1" + dependencies: + base64url "^2.0.0" + safe-buffer "^5.0.1" + +ee-first@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.0.tgz#6a0d7c6221e490feefd92ec3f441c9ce8cd097f4" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +elliptic@^6.0.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.2.tgz#e4c81e0829cf0a65ab70e998b8232723b5c1bc48" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + inherits "^2.0.1" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.0.0.tgz#d4596e702734a93e40e9af864319eabd99ff2f0e" + dependencies: + once "~1.3.0" + +engine.io-client@1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.2.tgz#c38767547f2a7d184f5752f6f0ad501006703766" + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "2.3.3" + engine.io-parser "1.3.2" + has-cors "1.1.0" + indexof "0.0.1" + parsejson "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + ws "1.1.1" + xmlhttprequest-ssl "1.5.3" + yeast "0.1.2" + +engine.io-parser@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.2.tgz#937b079f0007d0893ec56d46cb220b8cb435220a" + dependencies: + after "0.8.2" + arraybuffer.slice "0.0.6" + base64-arraybuffer "0.1.5" + blob "0.0.4" + has-binary "0.1.7" + wtf-8 "1.0.0" + +engine.io@1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.2.tgz#6b59be730b348c0125b0a4589de1c355abcf7a7e" + dependencies: + accepts "1.3.3" + base64id "1.0.0" + cookie "0.3.1" + debug "2.3.3" + engine.io-parser "1.3.2" + ws "1.1.1" + +enhanced-resolve@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.0.3.tgz#df14c06b5fc5eecade1094c9c5a12b4b3edc0b62" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + object-assign "^4.0.1" + tapable "^0.2.5" + +entities@1.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" + +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +errno@^0.1.1, errno@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" + dependencies: + prr "~0.0.0" + +error-ex@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" + dependencies: + is-arrayish "^0.2.1" + +error-inject@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" + +es-abstract@^1.5.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.6.1.tgz#bb8a2064120abcf928a086ea3d9043114285ec99" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.0" + is-callable "^1.1.3" + is-regex "^1.0.3" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +es6-object-assign@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.0.3.tgz#40a192e0fda5ee44ee8cf6f5b5d9b47cd0f69b14" + +es6-promise@^3.0.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + +escape-html@~1.0.1, escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@^1.3.0, etag@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" + +event-stream@0.6.x: + version "0.6.0" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-0.6.0.tgz#5601c6c61f595010d1eabfdc9265b1ad5e9902b8" + dependencies: + optimist "0.2" + +event-stream@~3.3.0: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +events-to-array@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" + +events@^1.0.0, events@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +evp_bytestokey@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53" + dependencies: + create-hash "^1.1.1" + +excel-export@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/excel-export/-/excel-export-0.5.1.tgz#6d08787f98b2ec931e4b3dcff18cc9083bbb8b77" + dependencies: + collections "^3.0.0" + node-zip "1.x" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +exit@0.1.2, exit@0.1.x: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +exports-loader@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/exports-loader/-/exports-loader-0.6.3.tgz#57dc78917f709b96f247fa91e69b554c855013c8" + dependencies: + loader-utils "0.2.x" + source-map "0.1.x" + +express@^4.10.2: + version "4.14.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.1" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "~2.2.0" + depd "~1.1.0" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + finalhandler "0.5.0" + fresh "0.3.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.2" + qs "6.2.0" + range-parser "~1.2.0" + send "0.14.1" + serve-static "~1.11.1" + type-is "~1.6.13" + utils-merge "1.0.0" + vary "~1.1.0" + +extend@^3.0.0, extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +external-editor@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + dependencies: + extend "^3.0.0" + spawn-sync "^1.0.15" + tmp "^0.0.29" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +extsprintf@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +fastparse@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +file-loader@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.9.0.tgz#1d2daddd424ce6d1b07cfe3f79731bed3617ab42" + dependencies: + loader-utils "~0.2.5" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +finalhandler@0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.4.1.tgz#85a17c6c59a94717d262d61230d4b0ebe3d4a14d" + dependencies: + debug "~2.2.0" + escape-html "~1.0.3" + on-finished "~2.3.0" + unpipe "~1.0.0" + +finalhandler@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" + dependencies: + debug "~2.2.0" + escape-html "~1.0.3" + on-finished "~2.3.0" + statuses "~1.3.0" + unpipe "~1.0.0" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-up@^1.0.0, find-up@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +for-each@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" + dependencies: + is-function "~1.0.0" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +foreground-child@^1.3.3, foreground-child@^1.5.3: + version "1.5.6" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" + dependencies: + cross-spawn "^4" + signal-exit "^3.0.0" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.11" + +form-data@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + +frameguard@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-2.0.0.tgz#30c2c149e5e3505f9e156f9bc491a438420e487e" + +fresh@0.3.0, fresh@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + +from@~0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.3.tgz#ef63ac2062ac32acf7862e0d40b44b896f22f3bc" + +fs-readdir-recursive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.0.17" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.17.tgz#8537f3f12272678765b4fd6528c0f1f66f8f4558" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +fstream@~0.1.21: + version "0.1.31" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-0.1.31.tgz#7337f058fbbbbefa8c9f561a28cab0849202c988" + dependencies: + graceful-fs "~3.0.2" + inherits "~2.0.0" + mkdirp "0.5" + rimraf "2" + +function-bind@^1.0.2, function-bind@^1.1.0, function-bind@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" + +gauge@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + supports-color "^0.2.0" + wide-align "^1.1.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^5.0.5: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^6.0.1: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@~7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^9.0.0: + version "9.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + +got@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca" + dependencies: + duplexify "^3.2.0" + infinity-agent "^2.0.0" + is-redirect "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + nested-error-stacks "^1.0.0" + object-assign "^3.0.0" + prepend-http "^1.0.0" + read-all-stream "^3.0.0" + timed-out "^2.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +graceful-fs@~3.0.2: + version "3.0.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" + dependencies: + natives "^1.1.0" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +handle-thing@^1.2.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" + +handlebars@^4.0.3: + version "4.0.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-binary@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + dependencies: + isarray "0.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has@^1.0.1, has@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hash.js@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573" + dependencies: + inherits "^2.0.1" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +helmet-csp@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-1.2.2.tgz#085c0307d57fc96cd97337f170ab8bfea99e5df7" + dependencies: + camelize "1.0.0" + content-security-policy-builder "1.0.0" + lodash.reduce "4.5.0" + platform "1.3.1" + +helmet@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-2.3.0.tgz#d655c85b55b0a3bf722a4c2c66e48b78b4161b91" + dependencies: + connect "3.4.1" + dns-prefetch-control "0.1.0" + dont-sniff-mimetype "1.0.0" + frameguard "2.0.0" + helmet-csp "1.2.2" + hide-powered-by "1.0.0" + hpkp "1.2.0" + hsts "1.0.0" + ienoopen "1.0.0" + nocache "1.0.1" + referrer-policy "1.0.0" + x-xss-protection "1.0.0" + +hide-powered-by@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +hpkp@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-1.2.0.tgz#83f2cb38b26cff21daf26e2ff4b57126921dec65" + +hsts@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsts/-/hsts-1.0.0.tgz#98e1039ef7aba554057b6b0e32584c0b1143a414" + dependencies: + core-util-is "1.0.2" + +html-comment-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" + +htmlparser2@3.8.x: + version "3.8.3" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" + dependencies: + domelementtype "1" + domhandler "2.3" + domutils "1.5" + entities "1.0" + readable-stream "1.1" + +http-assert@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.2.0.tgz#d6392e6f6519def4e340266b35096db6d3feba00" + dependencies: + deep-equal "~1.0.0" + http-errors "~1.4.0" + +http-deceiver@^1.2.4: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + +http-errors@^1.2.8, http-errors@^1.3.1, http-errors@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + dependencies: + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" + +http-errors@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.4.0.tgz#6c0242dea6b3df7afda153c71089b31c6e82aabf" + dependencies: + inherits "2.0.1" + statuses ">= 1.2.1 < 2" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" + +iconv-lite@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" + +iconv-lite@^0.2.11: + version "0.2.11" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" + +iconv-lite@~0.4.13: + version "0.4.15" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + +icss-replace-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +ienoopen@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b" + +ignore-by-default@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + +image-size@~0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.1.tgz#28eea8548a4b1443480ddddc1e083ae54652439f" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +infinity-agent@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216" + +inflation@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inline-style-prefixer@^0.6.7: + version "0.6.7" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-0.6.7.tgz#eeb453c2c764aa7471d1cc916c206fb81aca4e75" + dependencies: + bowser "^1.0.0" + +inquirer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" + dependencies: + ansi-escapes "^1.1.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + external-editor "^1.1.0" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.6" + pinkie-promise "^2.0.0" + run-async "^2.2.0" + rx "^4.1.0" + string-width "^2.0.0" + strip-ansi "^3.0.0" + through "^2.3.6" + +interpret@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" + +invariant@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ipaddr.js@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-function@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + +is-generator-function@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.6.tgz#9e71653cd15fff341c79c4151460a131d31e9fc4" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.12.4: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-regex@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.3.tgz#0d55182bddf9f2fde278220aec3a75642c908637" + +is-stream@^1.0.0, is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-svg@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" + dependencies: + html-comment-regex "^1.1.0" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isemail@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a" + +isexe@^1.0.0, isexe@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isomorphic-fetch@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.0-alpha, istanbul-lib-coverage@^1.0.0-alpha.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.0.tgz#c3f9b6d226da12424064cce87fce0fb57fdfa7a2" + +istanbul-lib-hook@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.0.tgz#fc5367ee27f59268e8f060b0c7aaf051d9c425c5" + dependencies: + append-transform "^0.4.0" + +istanbul-lib-instrument@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.4.2.tgz#0e2fdfac93c1dabf2e31578637dc78a19089f43e" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.13.0" + istanbul-lib-coverage "^1.0.0" + semver "^5.3.0" + +istanbul-lib-report@^1.0.0-alpha.3: + version "1.0.0-alpha.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0-alpha.3.tgz#32d5f6ec7f33ca3a602209e278b2e6ff143498af" + dependencies: + async "^1.4.2" + istanbul-lib-coverage "^1.0.0-alpha" + mkdirp "^0.5.1" + path-parse "^1.0.5" + rimraf "^2.4.3" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.0.tgz#9d429218f35b823560ea300a96ff0c3bbdab785f" + dependencies: + istanbul-lib-coverage "^1.0.0-alpha.0" + mkdirp "^0.5.1" + rimraf "^2.4.4" + source-map "^0.5.3" + +istanbul-reports@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.0.tgz#24b4eb2b1d29d50f103b369bd422f6e640aa0777" + dependencies: + handlebars "^4.0.3" + +j2c@^0.11.0, j2c@^0.11.2: + version "0.11.2" + resolved "https://registry.yarnpkg.com/j2c/-/j2c-0.11.2.tgz#b6508c55ee0c969d444d64d9147fe36d76c97b63" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +joi@^6.10.1: + version "6.10.1" + resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06" + dependencies: + hoek "2.x.x" + isemail "1.x.x" + moment "2.x.x" + topo "1.x.x" + +js-base64@^2.1.9: + version "2.1.9" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" + +js-tokens@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" + +js-tokens@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.0.tgz#a2f2a969caae142fb3cd56228358c89366957bd1" + +js-yaml@3.6.1, js-yaml@~3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +js-yaml@^3.2.7, js-yaml@^3.3.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +jshint-loader@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/jshint-loader/-/jshint-loader-0.8.3.tgz#6a16ce887e4d2f1bafbde0575e3c10f7bd2e694b" + dependencies: + loader-utils "0.2.x" + rcloader "=0.1.2" + strip-json-comments "0.1.x" + +jshint@^2.9.4: + version "2.9.4" + resolved "https://registry.yarnpkg.com/jshint/-/jshint-2.9.4.tgz#5e3ba97848d5290273db514aee47fe24cf592934" + dependencies: + cli "~1.0.0" + console-browserify "1.1.x" + exit "0.1.x" + htmlparser2 "3.8.x" + lodash "3.7.x" + minimatch "~3.0.2" + shelljs "0.3.x" + strip-json-comments "1.0.x" + +json-loader@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json3@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsonwebtoken@5.x.x: + version "5.7.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-5.7.0.tgz#1c90f9a86ce5b748f5f979c12b70402b4afcddb4" + dependencies: + jws "^3.0.0" + ms "^0.7.1" + xtend "^4.0.1" + +jsonwebtoken@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.2.1.tgz#0fc7217473fc02b4c9aa1e188aa70b51bba4fccb" + dependencies: + joi "^6.10.1" + jws "^3.1.4" + lodash.once "^4.0.0" + ms "^0.7.1" + xtend "^4.0.1" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +jszip@2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-2.5.0.tgz#7444fd8551ddf3e5da7198fea0c91bc8308cc274" + dependencies: + pako "~0.2.5" + +jwa@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5" + dependencies: + base64url "2.0.0" + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.9" + safe-buffer "^5.0.1" + +jws@^3.0.0, jws@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" + dependencies: + base64url "^2.0.0" + jwa "^1.1.4" + safe-buffer "^5.0.1" + +kdt@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/kdt/-/kdt-0.1.0.tgz#d54aadf92586c59b441519b4461b39fb7c5528f3" + +keygrip@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.1.tgz#b02fa4816eef21a8c4b35ca9e52921ffc89a30e9" + +kilometers-to-miles@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/kilometers-to-miles/-/kilometers-to-miles-1.0.3.tgz#26bbd1ab96fd7f7e0b28a258b2566b271c642bb3" + +kind-of@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + dependencies: + is-buffer "^1.0.2" + +koa-adapter-bluebird@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/koa-adapter-bluebird/-/koa-adapter-bluebird-0.0.1.tgz#495094fc71917f1d5ab1928b52b0279b69e17566" + dependencies: + bluebird "^3.1.1" + bluebird-co "^2.1.1" + is-generator-function "^1.0.3" + +koa-adapter@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/koa-adapter/-/koa-adapter-0.0.3.tgz#c2a3a4179f420185afa3c7978adc495073566f6e" + dependencies: + co "^4.6.0" + is-generator-function "^1.0.3" + +koa-bodyparser@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-2.3.0.tgz#236ed90a16f562e79cade2b958f67c848824e818" + dependencies: + co-body "^4.2.0" + copy-to "^2.0.1" + +koa-bunyan-logger@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/koa-bunyan-logger/-/koa-bunyan-logger-1.3.0.tgz#9a59908140c0b0f3c1c3a613aea24d4385bbbcbe" + dependencies: + bunyan "~1.5.0" + node-uuid "~1.4.1" + on-finished "~2.1.1" + +koa-compose@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" + dependencies: + any-promise "^1.1.0" + +koa-compress@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/koa-compress/-/koa-compress-1.0.9.tgz#a603036bedab1b9907ea77cca7d694673852e3f5" + dependencies: + bytes "^2.3.0" + compressible "^2.0.0" + koa-is-json "^1.0.0" + statuses "^1.0.0" + +koa-conditional-get@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/koa-conditional-get/-/koa-conditional-get-1.0.3.tgz#91aa03f2888aec0ae2f636f18b0cd95f158510c7" + +koa-convert@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" + dependencies: + co "^4.6.0" + koa-compose "^3.0.0" + +koa-etag@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/koa-etag/-/koa-etag-2.1.1.tgz#ab79894e027d0f09b1087a780e6babcca33af065" + dependencies: + etag "^1.3.0" + mz "^2.1.0" + +koa-generic-session@^1.11.4: + version "1.11.5" + resolved "https://registry.yarnpkg.com/koa-generic-session/-/koa-generic-session-1.11.5.tgz#430467152ccfc6f81baa944bad8683dd37df24ff" + dependencies: + copy-to "~2.0.1" + crc "~3.4.0" + debug "*" + parseurl "~1.3.1" + uid-safe "~2.1.1" + +koa-helmet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/koa-helmet/-/koa-helmet-2.0.0.tgz#0b85da9fcc6f1f6ac905bdb6023ff4a4b5d2b88d" + dependencies: + helmet "^2.1.1" + +koa-is-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" + +koa-jwt@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-jwt/-/koa-jwt-1.2.0.tgz#c0589c2c27d7e0b497a22cb28575d0bc7dc0f959" + dependencies: + jsonwebtoken "5.x.x" + koa-unless "0.0.1" + thunkify "~2.1.x" + +koa-morgan@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/koa-morgan/-/koa-morgan-1.0.1.tgz#08052e0ce0d839d3c43178b90a5bb3424bef1f99" + dependencies: + morgan "^1.6.1" + +koa-proxy@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/koa-proxy/-/koa-proxy-0.6.0.tgz#99f1860ff65fe167a865a5649d57a7dd3ad5cab0" + dependencies: + co-request "^0.2.0" + iconv-lite "^0.2.11" + +koa-response-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/koa-response-time/-/koa-response-time-1.0.2.tgz#35ea38df719fc7c1d2eddb8544a74b3650712884" + +koa-router@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/koa-router/-/koa-router-7.1.0.tgz#2fe6d7e6da7e3c46d8781953835c70513a6871f5" + dependencies: + debug "^2.2.0" + http-errors "^1.3.1" + koa-compose "^3.0.0" + methods "^1.0.1" + path-to-regexp "^1.1.1" + +koa-send@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-3.1.1.tgz#ef0af0f9a531ec817e88056b52b8e32d2e0ba91a" + dependencies: + co "^4.6.0" + debug "*" + mz "^2.3.1" + resolve-path "^1.3.1" + +koa-session@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/koa-session/-/koa-session-3.4.0.tgz#ce270291a4fcfbafe199abb64ccd9830e8c787bf" + dependencies: + debug "^2.2.0" + deep-equal "^1.0.0" + +koa-static@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-2.0.0.tgz#2693482e1a4c0219e6d926be1703a2658b754f26" + dependencies: + debug "*" + koa-send "~3.1.0" + +koa-unless@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/koa-unless/-/koa-unless-0.0.1.tgz#cfcdd1cdfbaf066e05d843e6a412df8a7c69b218" + +koa-unless@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/koa-unless/-/koa-unless-1.0.0.tgz#5aa57384bc882568afc90ac04852a3d58658aeeb" + +koa@2.0.0-alpha.7: + version "2.0.0-alpha.7" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.0.0-alpha.7.tgz#6e75c18d287c16b314ed1dc77e97c106b7b9e7fc" + dependencies: + accepts "^1.2.2" + content-disposition "~0.5.0" + content-type "^1.0.0" + cookies "~0.6.1" + debug "*" + delegates "^1.0.0" + depd "^1.1.0" + destroy "^1.0.3" + error-inject "~1.0.0" + escape-html "~1.0.1" + fresh "^0.3.0" + http-assert "^1.1.0" + http-errors "^1.2.8" + is-generator-function "^1.0.3" + koa-compose "^3.0.0" + koa-convert "^1.2.0" + koa-is-json "^1.0.0" + mime-types "^2.0.7" + on-finished "^2.1.0" + only "0.0.2" + parseurl "^1.3.0" + statuses "^1.2.0" + type-is "^1.5.5" + vary "^1.0.0" + +latest-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb" + dependencies: + package-json "^1.0.0" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +lcov-parse@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" + +less-loader@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-2.2.3.tgz#b6d8f8139c8493df09d992a93a00734b08f84528" + dependencies: + loader-utils "^0.2.5" + +less@^2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/less/-/less-2.7.2.tgz#368d6cc73e1fb03981183280918743c5dcf9b3df" + optionalDependencies: + errno "^0.1.1" + graceful-fs "^4.1.2" + image-size "~0.5.0" + mime "^1.2.11" + mkdirp "^0.5.0" + promise "^7.1.1" + request "^2.72.0" + source-map "^0.5.3" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +loader-runner@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.2.0.tgz#824c1b699c4e7a2b6501b85902d5b862bf45b3fa" + +loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.5, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5: + version "0.2.16" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +local-reverse-geocoder@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/local-reverse-geocoder/-/local-reverse-geocoder-0.2.2.tgz#0f0af54f97c0b5885ecd15ad0e963f657f3826df" + dependencies: + async "^2.0.1" + express "^4.10.2" + kdt "^0.1.0" + request "^2.75.0" + unzip2 "^0.2.5" + +lodash-es@^4.2.1: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash.assign@^3.0.0, lodash.assign@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + +lodash.clonedeep@^4.3.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + +lodash.defaults@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c" + dependencies: + lodash.assign "^3.0.0" + lodash.restparam "^3.0.0" + +lodash.indexof@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/lodash.indexof/-/lodash.indexof-4.0.5.tgz#53714adc2cddd6ed87638f893aa9b6c24e31ef3c" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0, lodash.isarray@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.isdate@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isdate/-/lodash.isdate-3.0.3.tgz#bd6b9be645e6ae6716b5ad007a08fbd1abd0b020" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.memoize@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + +lodash.reduce@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.5.0.tgz#af7d2ec621062441e77d5bf408a1e071ef86691c" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash.uniq@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +lodash@3.7.x: + version "3.7.0" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.7.0.tgz#3678bd8ab995057c07ade836ed2ef087da811d45" + +lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +lodash@~2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e" + +log-driver@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0, loose-envify@^1.1.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +lowercase-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +lru-cache@^4.0.1, lru-cache@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + dependencies: + pseudomap "^1.0.1" + yallist "^2.0.0" + +lucidlocation@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/lucidlocation/-/lucidlocation-0.0.1.tgz#b13490aff74b1aff14fbd52b6c3d4d000634962e" + +macaddress@^0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + +match-stream@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/match-stream/-/match-stream-0.0.2.tgz#99eb050093b34dffade421b9ac0b410a9cfa17cf" + dependencies: + buffers "~0.1.1" + readable-stream "~1.0.0" + +math-expression-evaluator@^1.2.14: + version "1.2.14" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.14.tgz#39511771ed9602405fba9affff17eb4d2a3843ab" + dependencies: + lodash.indexof "^4.0.5" + +md5-hex@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" + dependencies: + md5-o-matic "^0.1.1" + +md5-o-matic@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +merge-source-map@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.3.tgz#da1415f2722a5119db07b14c4f973410863a2abf" + dependencies: + source-map "^0.5.3" + +methods@^1.0.1, methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5, micromatch@^2.3.11: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +miller-rabin@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +"mime-db@>= 1.24.0 < 2", mime-db@~1.26.0: + version "1.26.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" + +mime-types@^2.0.7, mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: + version "2.1.14" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" + dependencies: + mime-db "~1.26.0" + +mime@1.2.x: + version "1.2.11" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + +mime@1.3.4, mime@^1.2.11: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +minimalistic-assert@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@1.2.0, minimist@^1.2.0, minimist@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minimist@~0.0.1, minimist@~0.0.5: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + +mithril-modal@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/mithril-modal/-/mithril-modal-0.0.1.tgz#2443cc5a1ceb3727784088a4837cbb5857a4eedc" + dependencies: + assign-styles "^2.0.0" + inline-style-prefixer "^0.6.7" + j2c "^0.11.0" + +mithril-objectify@3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/mithril-objectify/-/mithril-objectify-3.1.2.tgz#9eda474a977df8f1827025de420990d62583e1dc" + +mithril@0.2: + version "0.2.5" + resolved "https://registry.yarnpkg.com/mithril/-/mithril-0.2.5.tgz#c1a50438a93ac23f11ada91188bb784c755404c2" + +mkdirp@0.5, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +moment@2.x, moment@2.x.x, moment@^2.10.6, moment@^2.17.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + +morgan@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.7.0.tgz#eb10ca8e50d1abe0f8d3dad5c0201d052d981c62" + dependencies: + basic-auth "~1.0.3" + debug "~2.2.0" + depd "~1.1.0" + on-finished "~2.3.0" + on-headers "~1.0.1" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@0.7.2, ms@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +mute-stream@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + +mv@~2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" + dependencies: + mkdirp "~0.5.1" + ncp "~2.0.0" + rimraf "~2.4.0" + +mz@^2.1.0, mz@^2.3.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.6.0.tgz#c8b8521d958df0a4f2768025db69c719ee4ef1ce" + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nan@2.5.0, nan@^2.0.8, nan@^2.3.0, nan@^2.3.3: + version "2.5.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.0.tgz#aa8f1e34531d807e9e27755b234b4a6ec0c152a8" + +natives@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" + +ncp@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +nested-error-stacks@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz#19f619591519f096769a5ba9a86e6eeec823c3cf" + dependencies: + inherits "~2.0.1" + +nocache@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nocache/-/nocache-1.0.1.tgz#695c9f736926a7554f7365fa25e087941065bd36" + dependencies: + depd "1.1.0" + +node-fetch@^1.0.1, node-fetch@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-geocoder@^3.15.2: + version "3.15.2" + resolved "https://registry.yarnpkg.com/node-geocoder/-/node-geocoder-3.15.2.tgz#f017de31e8c9c6e437acfb1018abdbe1bc509498" + dependencies: + bluebird "^3.4.6" + request "^2.74.0" + request-promise "^4.1.1" + +node-libs-browser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.1.4" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "0.0.1" + os-browserify "^0.2.0" + path-browserify "0.0.0" + process "^0.11.0" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.0.5" + stream-browserify "^2.0.1" + stream-http "^2.3.1" + string_decoder "^0.10.25" + timers-browserify "^2.0.2" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@0.6.32, node-pre-gyp@^0.6.29: + version "0.6.32" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" + dependencies: + mkdirp "~0.5.1" + nopt "~3.0.6" + npmlog "^4.0.1" + rc "~1.1.6" + request "^2.79.0" + rimraf "~2.5.4" + semver "~5.3.0" + tar "~2.2.1" + tar-pack "~3.3.0" + +node-uuid@~1.4.1, node-uuid@~1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" + +node-zip@1.x: + version "1.1.1" + resolved "https://registry.yarnpkg.com/node-zip/-/node-zip-1.1.1.tgz#94d1ad674a3cd46a1588dd736f4a9a78c757eb62" + dependencies: + jszip "2.5.0" + +nodemon@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.11.0.tgz#226c562bd2a7b13d3d7518b49ad4828a3623d06c" + dependencies: + chokidar "^1.4.3" + debug "^2.2.0" + es6-promise "^3.0.2" + ignore-by-default "^1.0.0" + lodash.defaults "^3.1.2" + minimatch "^3.0.0" + ps-tree "^1.0.1" + touch "1.0.0" + undefsafe "0.0.3" + update-notifier "0.5.0" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + dependencies: + abbrev "1" + +nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-package-data@^2.3.2: + version "2.3.5" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + +normalize-url@^1.4.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.0.tgz#c2bb50035edee62cd81edb2d45da68dc25e3423e" + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +npmlog@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +nprogress@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +nyc@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/nyc/-/nyc-10.1.0.tgz#ca28b48f1bbefbfa75e14a2c4d02494c0a785242" + dependencies: + archy "^1.0.0" + arrify "^1.0.1" + caching-transform "^1.0.0" + convert-source-map "^1.3.0" + debug-log "^1.0.1" + default-require-extensions "^1.0.0" + find-cache-dir "^0.1.1" + find-up "^1.1.2" + foreground-child "^1.5.3" + glob "^7.0.6" + istanbul-lib-coverage "^1.0.0" + istanbul-lib-hook "^1.0.0" + istanbul-lib-instrument "^1.4.2" + istanbul-lib-report "^1.0.0-alpha.3" + istanbul-lib-source-maps "^1.1.0" + istanbul-reports "^1.0.0" + md5-hex "^1.2.0" + merge-source-map "^1.0.2" + micromatch "^2.3.11" + mkdirp "^0.5.0" + resolve-from "^2.0.0" + rimraf "^2.5.4" + signal-exit "^3.0.1" + spawn-wrap "1.2.4" + test-exclude "^3.3.0" + yargs "^6.6.0" + yargs-parser "^4.0.2" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + +object-inspect@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.2.1.tgz#3b62226eb8f6d441751c7d8f22a20ff80ac9dc3f" + +object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +obuf@^1.0.0, obuf@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e" + +on-finished@^2.1.0, on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-finished@~2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.1.1.tgz#f82ca1c9e3a4f3286b1b9938610e5b8636bd3cb2" + dependencies: + ee-first "1.1.0" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +once@~1.3.0, once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +only-shallow@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/only-shallow/-/only-shallow-1.2.0.tgz#71cecedba9324bc0518aef10ec080d3249dc2465" + +only@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + +opener@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.2.tgz#b32582080042af8680c389a499175b4c54fff523" + +optimist@0.2: + version "0.2.8" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.2.8.tgz#e981ab7e268b457948593b55674c099a815cac31" + dependencies: + wordwrap ">=0.0.1 <0.1.0" + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +options@>=0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + +os-browserify@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f" + +os-homedir@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.1.tgz#0d62bdf44b916fd3bbdcf2cab191948fb094f007" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-shim@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.0: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +"over@>= 0.0.5 < 1": + version "0.0.5" + resolved "https://registry.yarnpkg.com/over/-/over-0.0.5.tgz#f29852e70fd7e25f360e013a8ec44c82aedb5708" + +package-json@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0" + dependencies: + got "^3.2.0" + registry-url "^3.0.0" + +pako@~0.2.0, pako@~0.2.5: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +parse-asn1@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.0.0.tgz#35060f6d5015d37628c770f4e091a0b5a278bc23" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parsejson@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" + dependencies: + better-assert "~1.0.0" + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + dependencies: + better-assert "~1.0.0" + +parseurl@^1.3.0, parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-is-absolute@1.0.1, path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-to-regexp@^1.1.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + dependencies: + through "~2.3" + +pbkdf2@^3.0.3: + version "3.0.9" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.9.tgz#f2c4b25a600058b3c3773c086c37dbbee1ffe693" + dependencies: + create-hmac "^1.1.2" + +performance-now@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pikaday2@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pikaday2/-/pikaday2-2.0.1.tgz#0ab8ef954a805039fcd9c1d2eeab6b20b3f909f4" + dependencies: + lodash.assign "^3.2.0" + lodash.isarray "^3.0.4" + lodash.isdate "^3.0.1" + optionalDependencies: + moment "2.x" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +platform@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.1.tgz#492210892335bd3131c0a08dda2d93ec3543e423" + +pony@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pony/-/pony-1.0.0.tgz#25f0a71cab216d74f645e7e857558da84eb33f8d" + dependencies: + copy "~0.0.1" + inherits "~2.0.1" + minimist "~0.0.5" + readable-stream "~1.1.9" + smtp-protocol "~0.4.1" + +postcss-calc@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" + dependencies: + postcss "^5.0.2" + postcss-message-helpers "^2.0.0" + reduce-css-calc "^1.2.6" + +postcss-colormin@^2.1.8: + version "2.2.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.1.tgz#dc5421b6ae6f779ef6bfd47352b94abe59d0316b" + dependencies: + colormin "^1.0.5" + postcss "^5.0.13" + postcss-value-parser "^3.2.3" + +postcss-convert-values@^2.3.4: + version "2.6.0" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.0.tgz#08c6d06130fe58a91a21ff50829e1aad6a3a1acc" + dependencies: + postcss "^5.0.11" + postcss-value-parser "^3.1.2" + +postcss-discard-comments@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" + dependencies: + postcss "^5.0.14" + +postcss-discard-duplicates@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.0.2.tgz#02be520e91571ffb10738766a981d5770989bb32" + dependencies: + postcss "^5.0.4" + +postcss-discard-empty@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" + dependencies: + postcss "^5.0.14" + +postcss-discard-overridden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" + dependencies: + postcss "^5.0.16" + +postcss-discard-unused@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" + dependencies: + postcss "^5.0.14" + uniqs "^2.0.0" + +postcss-filter-plugins@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" + dependencies: + postcss "^5.0.4" + uniqid "^4.0.0" + +postcss-merge-idents@^2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" + dependencies: + has "^1.0.1" + postcss "^5.0.10" + postcss-value-parser "^3.1.1" + +postcss-merge-longhand@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" + dependencies: + postcss "^5.0.4" + +postcss-merge-rules@^2.0.3: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.1.tgz#5e5640020ce43cddd343c73bba91c9a358d1fe0f" + dependencies: + browserslist "^1.5.2" + caniuse-api "^1.5.2" + postcss "^5.0.4" + postcss-selector-parser "^2.2.2" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + +postcss-minify-font-values@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + dependencies: + object-assign "^4.0.1" + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-minify-gradients@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" + dependencies: + postcss "^5.0.12" + postcss-value-parser "^3.3.0" + +postcss-minify-params@^1.0.4: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.2" + postcss-value-parser "^3.0.2" + uniqs "^2.0.0" + +postcss-minify-selectors@^2.0.4: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" + dependencies: + alphanum-sort "^1.0.2" + has "^1.0.1" + postcss "^5.0.14" + postcss-selector-parser "^2.0.0" + +postcss-modules-extract-imports@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.0.1.tgz#8fb3fef9a6dd0420d3f6d4353cf1ff73f2b2a341" + dependencies: + postcss "^5.0.4" + +postcss-modules-local-by-default@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.1.1.tgz#29a10673fa37d19251265ca2ba3150d9040eb4ce" + dependencies: + css-selector-tokenizer "^0.6.0" + postcss "^5.0.4" + +postcss-modules-scope@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.0.2.tgz#ff977395e5e06202d7362290b88b1e8cd049de29" + dependencies: + css-selector-tokenizer "^0.6.0" + postcss "^5.0.4" + +postcss-modules-values@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.2.2.tgz#f0e7d476fe1ed88c5e4c7f97533a3e772ad94ca1" + dependencies: + icss-replace-symbols "^1.0.2" + postcss "^5.0.14" + +postcss-normalize-charset@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" + dependencies: + postcss "^5.0.5" + +postcss-normalize-url@^3.0.7: + version "3.0.8" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^1.4.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + +postcss-ordered-values@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.1" + +postcss-reduce-idents@^2.2.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-reduce-initial@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" + dependencies: + postcss "^5.0.4" + +postcss-reduce-transforms@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" + dependencies: + has "^1.0.1" + postcss "^5.0.8" + postcss-value-parser "^3.0.1" + +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.2.tgz#3d70f5adda130da51c7c0c2fc023f56b1374fe08" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^2.1.1: + version "2.1.6" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" + dependencies: + is-svg "^2.0.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + svgo "^0.7.0" + +postcss-unique-selectors@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss-zindex@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" + dependencies: + has "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.8: + version "5.2.10" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.10.tgz#b58b64e04f66f838b7bc7cb41f7dac168568a945" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.1.2" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +private@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process@^0.11.0: + version "0.11.9" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" + +promise@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf" + dependencies: + asap "~2.0.3" + +proxy-addr@~1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.2.0" + +prr@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" + +ps-tree@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" + dependencies: + event-stream "~3.3.0" + +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +public-encrypt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +pullstream@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/pullstream/-/pullstream-0.4.1.tgz#d6fb3bf5aed697e831150eb1002c25a3f8ae1314" + dependencies: + over ">= 0.0.5 < 1" + readable-stream "~1.0.31" + setimmediate ">= 1.0.2 < 2" + slice-stream ">= 1.0.0 < 2" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.3.2, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +q@^1.1.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + +qs@6.2.0, qs@~6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + +qs@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" + +qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +query-string@^4.1.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.1.tgz#54baada6713eafc92be75c47a731f2ebd09cd11d" + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0, querystring@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +raf@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.3.0.tgz#93845eeffc773f8129039f677f80a36044eee2c3" + dependencies: + performance-now "~0.2.0" + +random-bytes@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +randombytes@^2.0.0, randombytes@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@~2.1.2: + version "2.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.13" + unpipe "1.0.0" + +raw-loader@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" + +rc@^1.0.1, rc@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +rcfinder@~0.1.6: + version "0.1.9" + resolved "https://registry.yarnpkg.com/rcfinder/-/rcfinder-0.1.9.tgz#f3e80f387ddf9ae80ae30a4100329642eae81115" + dependencies: + lodash.clonedeep "^4.3.2" + +rcloader@=0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/rcloader/-/rcloader-0.1.2.tgz#a0963a6437d09ef8cb92d932d2dad497b0d1736c" + dependencies: + lodash "~2.4.1" + rcfinder "~0.1.6" + +read-all-stream@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" + dependencies: + pinkie-promise "^2.0.0" + readable-stream "^2.0.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +readable-stream@1.1, readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2, readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.1.5, readable-stream@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~1.0.0, readable-stream@~1.0.31: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +reduce-css-calc@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-function-call@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" + dependencies: + balanced-match "^0.4.2" + +redux-logger@^2.7.4: + version "2.7.4" + resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-2.7.4.tgz#891e5d29e7f111d08b5781a237b9965b5858c7f8" + dependencies: + deep-diff "0.3.4" + +redux@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/redux/-/redux-3.6.0.tgz#887c2b3d0b9bd86eca2be70571c27654c19e188d" + dependencies: + lodash "^4.2.1" + lodash-es "^4.2.1" + loose-envify "^1.1.0" + symbol-observable "^1.0.2" + +referrer-policy@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.0.0.tgz#f60eedc92f942b01a6118121ec932d66e8fd7e14" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz#257f41961ce44558b18f7814af48c17559f9faeb" + +regenerator-transform@0.9.8: + version "0.9.8" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +registry-url@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + dependencies: + is-finite "^1.0.0" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.1.1.tgz#26021e4f6f56fd4c309f6bf1ebd8c97a95ac1fb5" + dependencies: + bluebird "^3.4.1" + request-promise-core "1.1.1" + stealthy-require "^1.0.0" + +request@*, request@^2.72.0, request@^2.74.0, request@^2.75.0, request@^2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +request@2.75.0: + version "2.75.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.75.0.tgz#d2b8268a286da13eaa5d01adf5d18cc90f657d93" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + bl "~1.1.2" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.0.0" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + node-uuid "~1.4.7" + oauth-sign "~0.8.1" + qs "~6.2.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + +resolve-path@^1.3.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.3.3.tgz#4d83aba6468c2b8e632a575e3f52b0fa0dbe1a5c" + dependencies: + http-errors "~1.5.0" + path-is-absolute "1.0.1" + +resolve@^1.1.6, resolve@~1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + dependencies: + through "~2.3.4" + +rethink-handle-uncaught@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rethink-handle-uncaught/-/rethink-handle-uncaught-1.0.0.tgz#60b92a7febfc5c1e3bc12ba820c8d8b6527fa300" + +rethinkdbdash@^2.3.27: + version "2.3.27" + resolved "https://registry.yarnpkg.com/rethinkdbdash/-/rethinkdbdash-2.3.27.tgz#66de1c6cf13ed89db0c81ee0f060656caddfe1a5" + dependencies: + bluebird ">= 3.0.1" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.3.3, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.4, rimraf@~2.5.1, rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +rimraf@~2.4.0: + version "2.4.5" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" + dependencies: + glob "^6.0.1" + +ripemd160@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-1.0.1.tgz#93a4bbd4942bc574b69a8fa57c71de10ecca7d6e" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +rx@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + +safe-buffer@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" + +safe-json-stringify@~1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.0.3.tgz#3cb6717660a086d07cb5bd9b7a6875bcf67bd05e" + +sax@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +send@0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a" + dependencies: + debug "~2.2.0" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + fresh "0.3.0" + http-errors "~1.5.0" + mime "1.3.4" + ms "0.7.1" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.0" + +serve-static@~1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.14.1" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +"setimmediate@>= 1.0.2 < 2", setimmediate@^1.0.4, setimmediate@^1.0.5, setimmediate@~1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + +sha.js@^2.3.6: + version "2.4.8" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f" + dependencies: + inherits "^2.0.1" + +shelljs@0.3.x: + version "0.3.0" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1" + +shelljs@^0.7.0: + version "0.7.6" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.6.tgz#379cccfb56b91c8601e4793356eb5382924de9ad" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-2.1.2.tgz#375879b1f92ebc3b334480d038dc546a6d558564" + +signal-exit@^3.0.0, signal-exit@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +"slice-stream@>= 1.0.0 < 2": + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-stream/-/slice-stream-1.0.0.tgz#5b33bd66f013b1a7f86460b03d463dec39ad3ea0" + dependencies: + readable-stream "~1.0.31" + +slide@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +smtp-protocol@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/smtp-protocol/-/smtp-protocol-0.4.1.tgz#2d23a4af893b48e7c6d66530185e73d8b51c66f6" + dependencies: + event-stream "0.6.x" + stream-combiner "0.0.2" + through "~2.3.4" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +socket.io-adapter@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" + dependencies: + debug "2.3.3" + socket.io-parser "2.3.1" + +socket.io-client@1.7.2, socket.io-client@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.2.tgz#39fdb0c3dd450e321b7e40cfd83612ec533dd644" + dependencies: + backo2 "1.0.2" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "2.3.3" + engine.io-client "1.8.2" + has-binary "0.1.7" + indexof "0.0.1" + object-component "0.0.3" + parseuri "0.0.5" + socket.io-parser "2.3.1" + to-array "0.1.4" + +socket.io-parser@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" + dependencies: + component-emitter "1.1.2" + debug "2.2.0" + isarray "0.0.1" + json3 "3.3.2" + +socket.io@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.2.tgz#83bbbdf2e79263b378900da403e7843e05dc3b71" + dependencies: + debug "2.3.3" + engine.io "1.8.2" + has-binary "0.1.7" + object-assign "4.1.0" + socket.io-adapter "0.5.0" + socket.io-client "1.7.2" + socket.io-parser "2.3.1" + +socketio-sticky-session@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/socketio-sticky-session/-/socketio-sticky-session-0.4.2.tgz#7247a4be9c5e5684c731c5feddadd331194b8c65" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^0.1.4, source-list-map@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" + +source-map-support@^0.4.2: + version "0.4.10" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.10.tgz#d7b19038040a14c0837a18e630a196453952b378" + dependencies: + source-map "^0.5.3" + +source-map@0.1.x: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +spawn-sync@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + dependencies: + concat-stream "^1.4.7" + os-shim "^0.1.2" + +spawn-wrap@1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.2.4.tgz#920eb211a769c093eebfbd5b0e7a5d2e68ab2e40" + dependencies: + foreground-child "^1.3.3" + mkdirp "^0.5.0" + os-homedir "^1.0.1" + rimraf "^2.3.3" + signal-exit "^2.0.0" + which "^1.2.4" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +spdy-transport@^2.0.15: + version "2.0.18" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.0.18.tgz#43fc9c56be2cccc12bb3e2754aa971154e836ea6" + dependencies: + debug "^2.2.0" + hpack.js "^2.1.6" + obuf "^1.1.0" + readable-stream "^2.0.1" + wbuf "^1.4.0" + +spdy@^3.4.4: + version "3.4.4" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.4.tgz#e0406407ca90ff01b553eb013505442649f5a819" + dependencies: + debug "^2.2.0" + handle-thing "^1.2.4" + http-deceiver "^1.2.4" + select-hose "^2.0.0" + spdy-transport "^2.0.15" + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stack-utils@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-0.4.0.tgz#940cb82fccfa84e8ff2f3fdf293fe78016beccd1" + +"statuses@>= 1.2.1 < 2", "statuses@>= 1.3.1 < 2", statuses@^1.0.0, statuses@^1.2.0, statuses@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stealthy-require@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.0.0.tgz#1a8ed8fc19a8b56268f76f5a1a3e3832b0c26200" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-combiner@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.2.tgz#dfe0e74675742565e76c6056788ea5c23bd97db4" + dependencies: + duplexer "~0.0.3" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + dependencies: + duplexer "~0.1.1" + +stream-http@^2.3.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.6.2.tgz#bdfe40d2ee9262eb6bf2255bb3ad0ec0cdd6526d" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.1.0" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +string-length@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac" + dependencies: + strip-ansi "^3.0.0" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + +string.prototype.trim@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.0" + function-bind "^1.0.2" + +string_decoder@^0.10.25, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-json-comments@0.1.x: + version "0.1.3" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-0.1.3.tgz#164c64e370a8a3cc00c9e01b539e569823f0ee54" + +strip-json-comments@1.0.x, strip-json-comments@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +style-loader@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.13.1.tgz#468280efbc0473023cd3a6cd56e33b5a1d7fc3a9" + dependencies: + loader-utils "^0.2.7" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.0, supports-color@^3.1.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +svg-loader@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/svg-loader/-/svg-loader-0.0.2.tgz#601ab2fdaa1dadae3ca9975b550de92a07e1d92b" + +svgo@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.1.tgz#287320fed972cb097e72c2bb1685f96fe08f8034" + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.2.1" + js-yaml "~3.6.1" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +symbol-observable@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" + +tap-mocha-reporter@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/tap-mocha-reporter/-/tap-mocha-reporter-3.0.1.tgz#59abab0103b3453ca05df8f553ffe7b8cffac868" + dependencies: + color-support "^1.1.0" + debug "^2.1.3" + diff "^1.3.2" + escape-string-regexp "^1.0.3" + glob "^7.0.5" + js-yaml "^3.3.1" + tap-parser "^4.2.3" + unicode-length "^1.0.0" + optionalDependencies: + readable-stream "^2.1.5" + +tap-parser@^4.2.2, tap-parser@^4.2.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-4.2.4.tgz#65a2a602e49e17db83fa1f295f53fad03025cc4d" + dependencies: + events-to-array "^1.0.1" + js-yaml "^3.2.7" + optionalDependencies: + readable-stream "^2" + +tap@>=2.1.0: + version "9.0.3" + resolved "https://registry.yarnpkg.com/tap/-/tap-9.0.3.tgz#bd3deecb507f4e368486eeba8f10cd78f42f7283" + dependencies: + bluebird "^3.3.1" + clean-yaml-object "^0.1.0" + color-support "^1.1.0" + coveralls "^2.11.2" + deeper "^2.1.0" + foreground-child "^1.3.3" + glob "^7.0.0" + isexe "^1.0.0" + js-yaml "^3.3.1" + nyc "^10.0.0" + only-shallow "^1.0.2" + opener "^1.4.1" + os-homedir "1.0.1" + readable-stream "^2.0.2" + signal-exit "^3.0.0" + stack-utils "^0.4.0" + tap-mocha-reporter "^3.0.1" + tap-parser "^4.2.2" + tmatch "^3.0.0" + +tapable@^0.2.5, tapable@~0.2.5: + version "0.2.6" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d" + +tape@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.6.3.tgz#637e77581e9ab2ce17577e9bd4ce4f575806d8b6" + dependencies: + deep-equal "~1.0.1" + defined "~1.0.0" + for-each "~0.3.2" + function-bind "~1.1.0" + glob "~7.1.1" + has "~1.0.1" + inherits "~2.0.3" + minimist "~1.2.0" + object-inspect "~1.2.1" + resolve "~1.1.7" + resumer "~0.0.0" + string.prototype.trim "~1.1.2" + through "~2.3.8" + +tar-pack@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +test-exclude@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-3.3.0.tgz#7a17ca1239988c98367b0621456dbb7d4bc38977" + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.2.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.2.1.tgz#251fd1c80aff6e5cf57cb179ab1fcb724269bd11" + dependencies: + any-promise "^1.0.0" + +through@2, through@^2.3.6, through@~2.3, through@~2.3.1, through@~2.3.4, through@~2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +thunkify@~2.1.x: + version "2.1.2" + resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d" + +timed-out@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a" + +timers-browserify@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86" + dependencies: + setimmediate "^1.0.4" + +timezones.json@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/timezones.json/-/timezones.json-1.1.0.tgz#709693f4e3250f99ec21401dc00224b68cd1aac9" + +tmatch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-3.0.0.tgz#7d2071dedbbc587f194acda3067bd0747b670991" + +tmp@^0.0.29: + version "0.0.29" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + dependencies: + os-tmpdir "~1.0.1" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + +topo@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5" + dependencies: + hoek "2.x.x" + +touch@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de" + dependencies: + nopt "~1.0.10" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +translate.js@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/translate.js/-/translate.js-0.5.0.tgz#01c1d3bbead8dc7a6f77e7efc442d662a2acfcfd" + +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-is@^1.5.5, type-is@~1.6.13, type-is@~1.6.6: + version "1.6.14" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.13" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uglify-js@^2.6, uglify-js@^2.7.5: + version "2.7.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + dependencies: + async "~0.2.6" + source-map "~0.5.1" + uglify-to-browserify "~1.0.0" + yargs "~3.10.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +uid-safe@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.3.tgz#077e264a00b3187936b270bb7376a26473631071" + dependencies: + base64-url "1.3.3" + random-bytes "~1.0.0" + +ultron@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + +undefsafe@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f" + +unicode-length@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/unicode-length/-/unicode-length-1.0.3.tgz#5ada7a7fed51841a418a328cf149478ac8358abb" + dependencies: + punycode "^1.3.2" + strip-ansi "^3.0.1" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +uniqid@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" + dependencies: + macaddress "^0.2.8" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unzip2@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/unzip2/-/unzip2-0.2.5.tgz#4ef7a579a78c15c51f550f6a053db194149c8992" + dependencies: + binary "~0.3.0" + fstream "~0.1.21" + match-stream "~0.0.2" + pullstream "~0.4.0" + readable-stream "~1.0.0" + setimmediate "~1.0.1" + +update-notifier@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-0.5.0.tgz#07b5dc2066b3627ab3b4f530130f7eddda07a4cc" + dependencies: + chalk "^1.0.0" + configstore "^1.0.0" + is-npm "^1.0.0" + latest-version "^1.0.0" + repeating "^1.1.2" + semver-diff "^2.0.0" + string-length "^1.0.0" + +url-loader@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.7.tgz#67e8779759f8000da74994906680c943a9b0925d" + dependencies: + loader-utils "0.2.x" + mime "1.2.x" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3, util@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +v8flags@^2.0.10: + version "2.0.11" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" + dependencies: + user-home "^1.1.1" + +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +validator@4.8: + version "4.8.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-4.8.0.tgz#be7e4ddaa346305a235ffba255fa98e0bf45db1d" + dependencies: + depd "1.1.0" + +vary@^1.0.0, vary@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + +velocity-animate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/velocity-animate/-/velocity-animate-1.4.0.tgz#b220a79cecfcdceeaf66c44e09ee9532bf5fcea5" + +vendors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +verror@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.9.0.tgz#107a8a2d14c33586fc4bb830057cd2d19ae2a6ee" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +watchpack@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.2.0.tgz#15d4620f1e7471f13fcb551d5c030d2c3eb42dbb" + dependencies: + async "^2.1.2" + chokidar "^1.4.3" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.4.0: + version "1.7.2" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.2.tgz#d697b99f1f59512df2751be42769c1580b5801fe" + dependencies: + minimalistic-assert "^1.0.0" + +weak-map@~1.0.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/weak-map/-/weak-map-1.0.5.tgz#79691584d98607f5070bd3b70a40e6bb22e401eb" + +webpack-sources@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.4.tgz#ccc2c817e08e5fa393239412690bb481821393cd" + dependencies: + source-list-map "~0.1.7" + source-map "~0.5.3" + +webpack@2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.2.0.tgz#09246336b5581c9002353f75bcadb598a648f977" + dependencies: + acorn "^4.0.4" + acorn-dynamic-import "^2.0.0" + ajv "^4.7.0" + ajv-keywords "^1.1.1" + async "^2.1.2" + enhanced-resolve "^3.0.0" + interpret "^1.0.0" + json-loader "^0.5.4" + loader-runner "^2.2.0" + loader-utils "^0.2.16" + memory-fs "~0.4.1" + mkdirp "~0.5.0" + node-libs-browser "^2.0.0" + source-map "^0.5.3" + supports-color "^3.1.0" + tapable "~0.2.5" + uglify-js "^2.7.5" + watchpack "^1.2.0" + webpack-sources "^0.1.4" + yargs "^6.0.0" + +whatwg-fetch@>=0.10.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.1.tgz#078b9461bbe91cea73cbce8bb122a05f9e92b772" + +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which@^1.2.4, which@^1.2.9: + version "1.2.12" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + dependencies: + isexe "^1.1.1" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +windrose@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/windrose/-/windrose-2.0.2.tgz#67b62d5e412e614e680e626a7b00156de147709a" + +wordwrap@0.0.2, "wordwrap@>=0.0.1 <0.1.0", wordwrap@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^1.1.2, write-file-atomic@^1.1.4: + version "1.3.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + +ws@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + +wtf-8@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + +x-xss-protection@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.0.0.tgz#898afb93869b24661cf9c52f9ee8db8ed0764dd9" + +xdg-basedir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + dependencies: + os-homedir "^1.0.0" + +xmlhttprequest-ssl@1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" + +xtend@^4.0.0, xtend@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" + +yargs-parser@^4.0.2, yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + dependencies: + camelcase "^3.0.0" + +yargs@^6.0.0, yargs@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^4.2.0" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"