├── .npmrc ├── test-reports └── unit │ └── .gitkeep ├── .gitignore ├── screenshot.png ├── .prettierrc.yaml ├── bin └── index.js ├── .eslintignore ├── .travis.yml ├── .editorconfig ├── CHANGELOG.md ├── jest.config.js ├── release.config.js ├── LICENSE ├── src ├── runner.js ├── __snapshots__ │ └── activeWinLog.spec.js.snap ├── activeWinLog.spec.js └── activeWinLog.js ├── commitMessageConfig.js ├── .eslintrc.js ├── fixtures ├── awl.json ├── compressed.json └── uncompressed.json ├── README.md ├── package.json ├── DEVELOPERS.md └── CONTRIBUTING.md /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true 2 | -------------------------------------------------------------------------------- /test-reports/unit/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test-reports/ 3 | TEMPLATE_NPM_PROJECT.md 4 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uglow/active-win-log/HEAD/screenshot.png -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | # .prettierrc 2 | printWidth: 120 3 | singleQuote: true 4 | trailingComma: es5 5 | -------------------------------------------------------------------------------- /bin/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const runner = require('../src/runner.js'); 3 | runner.run(process.argv); 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Common folders to ignore 2 | node_modules/* 3 | bower_components/* 4 | 5 | # Config folder (optional - you might want to lint this...) 6 | config/* 7 | 8 | # Ignore the commitMessageConfig.js, as it has specific formatting 9 | commitMessageConfig.js 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - '10' 5 | 6 | script: 7 | - npm run verify 8 | - npm run test:report 9 | 10 | after_success: 11 | - npm run upload-coverage 12 | - npm run semantic-release 13 | 14 | branches: 15 | except: 16 | - /^v\d+\.\d+\.\d+$/ 17 | 18 | notifications: 19 | email: 20 | recipients: 21 | - u_glow@hotmail.com 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor Config - generated by Confit. This file will NOT be re-overwritten by Confit 2 | # Feel free to customise it further. 3 | # http://editorconfig.org 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.0.3](https://github.com/uglow/active-win-log/compare/v1.0.2...v1.0.3) (2021-03-11) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * **log:** update active-win dep to fix OSX issues ([e81ba30](https://github.com/uglow/active-win-log/commit/e81ba3010f1121fd70a930b990a1e32ced5a2e3f)) 7 | * **log:** update active-win dep to fix OSX issues ([42bfa6b](https://github.com/uglow/active-win-log/commit/42bfa6bf7d9a3f4bfaee879c0eb3a8e4b1d9a275)), closes [#1](https://github.com/uglow/active-win-log/issues/1) 8 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // Coverage only shows for Vue components that have data, methods, or computed properties 2 | // See https://github.com/vuejs/vue-cli/issues/1879#issuecomment-412300256 3 | 4 | module.exports = { 5 | moduleFileExtensions: ['js', 'json'], 6 | testMatch: ['/src/**/*.spec.js'], 7 | testEnvironment: 'node', 8 | automock: false, 9 | 10 | reporters: ['default'], 11 | 12 | collectCoverageFrom: ['src/**/*.js', '!src/runner.js'], 13 | coverageReporters: ['lcov', 'json-summary', 'html', 'text', 'text-summary'], 14 | coverageDirectory: '/test-reports/coverage', 15 | coverageThreshold: { 16 | global: { 17 | statements: 80, 18 | branches: 80, 19 | functions: 75, 20 | lines: 80, 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | branches: ['master'], 3 | plugins: [ 4 | '@semantic-release/commit-analyzer', 5 | '@semantic-release/release-notes-generator', 6 | ['@semantic-release/changelog', { changelogFile: 'CHANGELOG.md' }], 7 | '@semantic-release/npm', 8 | [ 9 | '@semantic-release/github', 10 | { 11 | assets: ['*'], 12 | }, 13 | ], 14 | [ 15 | '@semantic-release/git', 16 | { 17 | assets: ['CHANGELOG.md', 'package.json'], // Commit changelog and package.json back to git, and don't trigger a build (skip ci) 18 | // eslint-disable-next-line no-template-curly-in-string 19 | message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}', 20 | }, 21 | ], 22 | ], 23 | }; 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | active-win-log Copyright (c) 2019 Brett Uglow 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /src/runner.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { ActiveWinLog, COMMANDS } = require('./activeWinLog'); 4 | 5 | async function run(args = '') { 6 | // Before we try to run anything in the background, just check the args 7 | const awl = new ActiveWinLog(); 8 | await awl.init(); 9 | 10 | const firstArg = args.length > 2 ? args[2] : ''; 11 | const secondArg = args.length > 3 ? args[3] : '_'; 12 | 13 | // Show the help if there is an argument AND it is the help command OR it does not match any command 14 | if (firstArg && (firstArg === COMMANDS.HELP || !Object.values(COMMANDS).includes(firstArg))) { 15 | console.log(awl.showHelp()); 16 | return; 17 | } 18 | 19 | if (firstArg === COMMANDS.PRINT) { 20 | console.log(await awl.getStats({ lastNDays: !isNaN(Number(secondArg)) ? secondArg : 1 })); 21 | return; 22 | } 23 | 24 | if (firstArg === COMMANDS.QUIT) { 25 | console.log('Stopping active-win-log...'); 26 | await awl.killExistingProcess(); 27 | console.log('Stopped.'); 28 | return; 29 | } 30 | 31 | // Kill the existing process if it exists 32 | await awl.killExistingProcess(); 33 | 34 | console.log('Running active-win-log in the background. Type `awl -q` to stop it running.'); 35 | 36 | // Now run the script in the background again 37 | if (process.env.DEBUG_MODE === 'true') { 38 | awl.run(); 39 | } else { 40 | require('daemonize-process')(); 41 | awl.run(); 42 | } 43 | } 44 | 45 | module.exports = { 46 | run, 47 | }; 48 | -------------------------------------------------------------------------------- /commitMessageConfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | 5 | types: [ 6 | {value: 'feat', name: 'feat: A new feature'}, 7 | {value: 'fix', name: 'fix: A bug fix'}, 8 | {value: 'docs', name: 'docs: Documentation only changes'}, 9 | {value: 'style', name: 'style: Changes that do not affect the meaning of the code\n (white-space, formatting, missing semi-colons, etc)'}, 10 | {value: 'refactor', name: 'refactor: A code change that neither fixes a bug nor adds a feature'}, 11 | {value: 'perf', name: 'perf: A code change that improves performance'}, 12 | {value: 'test', name: 'test: Adding missing tests'}, 13 | {value: 'chore', name: 'chore: Changes to the build process or auxiliary tools\n and libraries such as documentation generation'}, 14 | {value: 'revert', name: 'revert: Revert to a commit'}, 15 | {value: 'WIP', name: 'WIP: Work in progress'} 16 | ], 17 | 18 | scopes: [ 19 | {name: 'build'}, 20 | {name: 'ci'}, 21 | {name: 'log'}, 22 | {name: 'readme'}, 23 | ], 24 | 25 | // it needs to match the value for field type. Eg.: 'fix' 26 | /* 27 | scopeOverrides: { 28 | fix: [ 29 | 30 | {name: 'merge'}, 31 | {name: 'style'}, 32 | {name: 'e2eTest'}, 33 | {name: 'unitTest'} 34 | ] 35 | }, 36 | */ 37 | 38 | allowCustomScopes: false, 39 | allowBreakingChanges: ['feat', 'fix'], 40 | appendBranchNameToCommitMessage: false, 41 | }; 42 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | parser: 'babel-eslint', 5 | ecmaVersion: 2018, 6 | sourceType: 'module', 7 | }, 8 | env: { 9 | es6: true, 10 | node: true, 11 | jest: true, 12 | }, 13 | extends: [ 14 | 'eslint:recommended', 15 | 'plugin:import/errors', 16 | 'plugin:import/warnings', 17 | 'plugin:node/recommended', 18 | 'plugin:prettier/recommended', 19 | ], 20 | 21 | plugins: ['node', 'filenames', 'prettier'], 22 | 23 | // add your custom rules here 24 | rules: { 25 | 'prefer-const': 'error', 26 | 'no-var': 'error', 27 | 28 | // Turn off this rule as it is needed for web-component-lib integration (Nuxt.js doesn't like ESM files, yet) 29 | 'import/no-webpack-loader-syntax': 'off', 30 | 'import/no-unresolved': 'off', 31 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 32 | 'no-debugger': process.env.NODnE_ENV === 'production' ? 'error' : 'off', 33 | 34 | // Turn off node/no-unsupported-features because it complains about import & export 35 | 'node/no-unsupported-features': 'off', 36 | 37 | // Avoid one-line if and else statements 38 | curly: ['error', 'all'], 39 | 40 | 'filenames/match-regex': ['error', /^(_*[a-z0-9.]+)([A-Z][a-z0-9.]+)*$/g], // Added an '_*' to support Nuxt _something.vue pages 41 | 'filenames/match-exported': ['error', 'camel'], 42 | 'filenames/no-index': 'off', 43 | 44 | "prettier/prettier": "error" 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /fixtures/awl.json: -------------------------------------------------------------------------------- 1 | { 2 | "pid": 64013, 3 | "stats": { 4 | "2019-03-20": { 5 | "WebStorm": { 6 | "word-domination-plan-703": [ 7 | "2019-03-20T10:44:51.168Z" 8 | ] 9 | }, 10 | "Sublime": { 11 | "manifesto.txt": [ 12 | "2019-03-20T10:44:56.198Z" 13 | ] 14 | }, 15 | "Google": { 16 | "How to be good at things": [ 17 | "2019-03-20T10:45:06.266Z", 18 | "2019-03-20T10:45:11.297Z", 19 | "2019-03-20T10:45:16.326Z", 20 | "2019-03-20T10:45:21.356Z", 21 | "2019-03-20T10:45:26.356Z", 22 | "2019-03-20T10:45:31.356Z", 23 | "2019-03-20T10:45:36.356Z", 24 | "2019-03-20T10:45:41.356Z" 25 | ] 26 | } 27 | }, 28 | "2019-03-22": { 29 | "WebStorm": { 30 | "active-win-log [/mydev/code/npm/active-win-log] - .../src/activeWinLog.js [active-win-log]": [ 31 | "2019-03-22T10:44:51.168Z" 32 | ] 33 | }, 34 | "Sublime Text": { 35 | "awl.json": [ 36 | "2019-03-22T10:44:56.198Z" 37 | ] 38 | }, 39 | "Google Chrome": { 40 | "table - npm": [ 41 | "2019-03-22T10:45:01.234Z" 42 | ], 43 | "Creating a real-world CLI app with Node": [ 44 | "2019-03-22T10:45:06.266Z", 45 | "2019-03-22T10:45:11.297Z", 46 | "2019-03-22T10:45:16.326Z", 47 | "2019-03-22T10:45:21.356Z" 48 | ], 49 | "": [ 50 | "2019-03-22T10:45:26.387Z" 51 | ] 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/__snapshots__/activeWinLog.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`ActiveWinLog getStats() should render stats from a (fixture) log file 1`] = ` 4 | "2019-03-20 00:00:50 5 | WebStorm 00:00:05 6 | word-domination-plan-703 00:00:05 7 | Sublime 00:00:05 8 | manifesto.txt 00:00:05 9 | Google 00:00:40 10 | How to be good at things 00:00:40 11 | 12 | 2019-03-22 00:00:40 13 | WebStorm 00:00:05 14 | active-win-log [/mydev/code/npm/active-win-log] 00:00:05 15 | Sublime Text 00:00:05 16 | awl.json 00:00:05 17 | Google Chrome 00:00:30 18 | table - npm 00:00:05 19 | Creating a real-world CLI app with Node 00:00:20 20 |  00:00:05 21 | " 22 | `; 23 | 24 | exports[`ActiveWinLog showHelp() should display a help message 1`] = ` 25 | Array [ 26 | "", 27 | "Usage: awl ", 28 | "awl Start monitoring the active window", 29 | "awl -? This help information", 30 | "awl -l n Display statistics for the last \\"n\\" days in the log", 31 | "awl -q Stop monitoring", 32 | "Global log location: foo.json", 33 | ] 34 | `; 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # active-win-log 2 | 3 | > A command line tool for logging time spent viewing application windows. 4 | 5 | [![NPM Version](https://img.shields.io/npm/v/active-win-log.svg?style=flat-square)](http://npm.im/active-win-log) 6 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 7 | [![Coverage Status](https://coveralls.io/repos/github/uglow/active-win-log/badge.svg?branch=master)](https://coveralls.io/github/uglow/active-win-log?branch=master) 8 | [![Dependencies status](https://david-dm.org/uglow/active-win-log/status.svg?theme=shields.io)](https://david-dm.org/uglow/active-win-log#info=dependencies) 9 | [![Dev-dependencies status](https://david-dm.org/uglow/active-win-log/dev-status.svg?theme=shields.io)](https://david-dm.org/uglow/active-win-log#info=devDependencies) 10 | 11 | 12 | ## Install 13 | 14 | npm install -g active-win-log 15 | 16 | 17 | ## Usage 18 | 19 | ``` 20 | $ awl -? 21 | 22 | Usage: awl 23 | awl Start monitoring the active window 24 | awl -? This help information 25 | awl -l n Display statistics for the last "n" days in the log 26 | awl -q Stop monitoring 27 | Log location: /users//.active-win-log/awl.json 28 | 29 | ``` 30 | 31 | ## Sample output 32 | Command: `awl -l 1` 33 | ![screen shot](screenshot.png) 34 | 35 | ## Contributing 36 | 37 | PRs are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md). 38 | 39 | ## Motivation 40 | 41 | I use this tool to give me a better sense of how I am spending my time when working out of the office. The tool checks 42 | to see what the active window is (using [active-win](https://www.npmjs.com/package/active-win)) _every 5 seconds_. 43 | 44 | ## Troubleshooting 45 | 46 | ### "I start `awl` but it just shows the pid and an empty stats object" 47 | 48 | This may be due to changes in MacOS 10.15 and later, which requires the `[active-win](https://github.com/sindresorhus/active-win)` 49 | library (which `active-win-log` depends on) to prompt for access when the library attempts to read a process' window title. 50 | 51 | In the meantime, if you want `active-win-log` to work, you must grant access to your terminal program when OSX 52 | prompts for Accessibility and/or Screen-Recording access. (I know, this really sucks, but it's an OSX limitation. 53 | If you think you can improve this behaviour, see [this issue](https://github.com/sindresorhus/active-win/issues/97).) 54 | 55 | ## License 56 | 57 | This software is licensed under the MIT Licence. See [LICENSE](LICENSE). 58 | 59 | 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "active-win-log", 3 | "version": "1.0.3", 4 | "description": "A window logging tool that tracks application usage", 5 | "keywords": [ 6 | "activity", 7 | "time-tracker", 8 | "timesheet", 9 | "usage", 10 | "macos", 11 | "linux", 12 | "windows", 13 | "app", 14 | "application", 15 | "window", 16 | "win", 17 | "active", 18 | "focused" 19 | ], 20 | "license": "MIT", 21 | "author": "Brett Uglow (http://uglow.github.io/)", 22 | "main": "bin/index.js", 23 | "bin": { 24 | "awl": "bin/index.js" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/uglow/active-win-log.git" 29 | }, 30 | "files": [ 31 | "bin", 32 | "CONTRIBUTING.md", 33 | "src/*.js", 34 | "src/runner.js", 35 | "!src/*.spec.js" 36 | ], 37 | "scripts": { 38 | "pre-release": "npm-run-all verify test:report ", 39 | "start": "./bin/index.js", 40 | "test": "npm run test:unit", 41 | "test:unit": "jest", 42 | "test:report": "jest --no-cache --coverage --json --outputFile=test-reports/unit/unit.json", 43 | "test:reporthtml": "jest --coverage", 44 | "test:watch": "jest --watchAll", 45 | "upload-coverage": "coveralls < test-reports/coverage/lcov.info", 46 | "lint": "eslint --max-warnings=0 --fix src/", 47 | "verify": "eslint --max-warnings=0 src/", 48 | "semantic-release": "semantic-release" 49 | }, 50 | "config": { 51 | "commitizen": { 52 | "path": "node_modules/cz-customizable" 53 | }, 54 | "cz-customizable": { 55 | "config": "commitMessageConfig.js" 56 | } 57 | }, 58 | "gitHooks": { 59 | "commit-msg": "cz-customizable-ghooks", 60 | "pre-push": "npm run pre-release" 61 | }, 62 | "dependencies": { 63 | "active-win": "6.3.0", 64 | "ansi-colors": "3.2.4", 65 | "daemonize-process": "2.0.1", 66 | "userhome": "1.0.0" 67 | }, 68 | "devDependencies": { 69 | "@semantic-release/changelog": "5.0.1", 70 | "@semantic-release/git": "9.0.0", 71 | "coveralls": "3.1.0", 72 | "cross-env": "5.0.5", 73 | "cz-customizable": "5.2.0", 74 | "cz-customizable-ghooks": "1.5.0", 75 | "eslint": "4.19.1", 76 | "eslint-config-prettier": "4.1.0", 77 | "eslint-plugin-filenames": "1.3.2", 78 | "eslint-plugin-import": "2.13.0", 79 | "eslint-plugin-node": "6.0.1", 80 | "eslint-plugin-prettier": "3.0.1", 81 | "jest": "26.6.3", 82 | "mock-stdin": "0.3.1", 83 | "npm-run-all": "4.0.2", 84 | "prettier": "1.16.4", 85 | "semantic-release": "17.4.1", 86 | "yorkie": "2.0.0" 87 | }, 88 | "engines": { 89 | "node": ">=8.x" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/activeWinLog.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mockActiveWin = jest.fn(); 4 | jest.mock('active-win', () => mockActiveWin); 5 | 6 | const { ActiveWinLog } = require('./activeWinLog.js'); 7 | const path = require('path'); 8 | const userhome = require('userhome'); 9 | 10 | describe('ActiveWinLog', () => { 11 | afterEach(() => { 12 | jest.clearAllMocks(); 13 | }); 14 | 15 | describe('init()', () => { 16 | it('should set the logFile to the users home directory by default', async () => { 17 | const awl = new ActiveWinLog({}); 18 | await awl.init(); 19 | expect(awl.logFile).toEqual(path.join(userhome('.active-win-log'), 'awl.json')); 20 | }); 21 | }); 22 | 23 | describe('showHelp()', () => { 24 | it('should display a help message', () => { 25 | const awl = new ActiveWinLog({ logFile: 'foo.json' }); 26 | const output = awl.showHelp().split('\n'); 27 | 28 | expect(output).toMatchSnapshot(); 29 | }); 30 | }); 31 | 32 | describe('getStats()', () => { 33 | it('should render stats from a (fixture) log file', async () => { 34 | const awl = new ActiveWinLog({ logFile: path.join(__dirname, '../fixtures/awl.json') }); 35 | const output = await awl.getStats({ lastNDays: 2 }); 36 | 37 | expect(output).toMatchSnapshot(); 38 | }); 39 | }); 40 | 41 | describe('recordActiveWin()', () => { 42 | it('should not write to the log file when the active-win library returns a falsey value', async () => { 43 | const awl = new ActiveWinLog({ logFile: path.join(__dirname, '../fixtures/awl.json') }); 44 | awl.getLogFileData = jest.fn(); 45 | awl.setLogFileData = jest.fn(); 46 | mockActiveWin.mockResolvedValue(null); 47 | 48 | await awl.recordActiveWin(); 49 | 50 | // We bailed, so neither method was called 51 | expect(awl.getLogFileData).not.toHaveBeenCalled(); 52 | expect(awl.setLogFileData).not.toHaveBeenCalled(); 53 | }); 54 | 55 | it('should not write to the log file when the active-win library throws an error', async () => { 56 | const awl = new ActiveWinLog({ logFile: path.join(__dirname, '../fixtures/awl.json') }); 57 | awl.getLogFileData = jest.fn(); 58 | awl.setLogFileData = jest.fn(); 59 | mockActiveWin.mockRejectedValue(new Error('Test: something went wrong')); 60 | 61 | await awl.recordActiveWin(); 62 | 63 | // We bailed, so neither method was called 64 | expect(awl.getLogFileData).not.toHaveBeenCalled(); 65 | expect(awl.setLogFileData).not.toHaveBeenCalled(); 66 | }); 67 | 68 | it('should write the active-win window information to the log file', async () => { 69 | const awl = new ActiveWinLog({ logFile: path.join(__dirname, '../fixtures/awl.json') }); 70 | awl.getLogFileData = jest.fn().mockResolvedValue({ stats: {} }); 71 | awl.setLogFileData = jest.fn(); 72 | mockActiveWin.mockResolvedValue({ 73 | title: 'garbo.org', 74 | owner: { 75 | name: 'FireFox', 76 | }, 77 | }); 78 | 79 | await awl.recordActiveWin('2019-03-22T10:45:01.234Z'); 80 | 81 | // We bailed, so neither method was called 82 | expect(awl.getLogFileData).toHaveBeenCalled(); 83 | expect(awl.setLogFileData).toHaveBeenCalledWith({ 84 | stats: { 85 | '2019-03-22': { 86 | FireFox: { 87 | 'garbo.org': ['2019-03-22T10:45:01.234Z'], 88 | }, 89 | }, 90 | }, 91 | }); 92 | }); 93 | }); 94 | }); 95 | -------------------------------------------------------------------------------- /DEVELOPERS.md: -------------------------------------------------------------------------------- 1 | # Building and Testing this project 2 | 3 | This document describes how to set up your development environment to build and test this project. 4 | It also explains the basic mechanics of using `git` and `node` 5 | 6 | - [Prerequisite Software](#prerequisite-software) 7 | - [Project Organisation](#project-organisation) 8 | - [Installing NPM Modules](#installing) 9 | - [Running Tests](#running-tests) 10 | - [Formatting your Source Code](#formatting-your-source-code) 11 | - [Linting/verifying your Source Code](#lintingverifying-your-source-code) 12 | - [Semantic Release setup](#semantic-release-setup) 13 | 14 | See the [contribution guidelines][contributing] if you'd like to contribute to this project. 15 | 16 | ## Prerequisite Software 17 | 18 | Before you can build and test this project, you must install and configure the 19 | following products on your development machine: 20 | 21 | - [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or 22 | [Windows](http://windows.github.com)); [GitHub's Guide to Installing 23 | Git](https://help.github.com/articles/set-up-git) is a good source of information. 24 | 25 | - [Node.js](http://nodejs.org), (version specified in the engines field of [`package.json`](package.json)) which is used to run tests. 26 | 27 | ## Project organisation 28 | 29 | The project is organised into the following folder structure: 30 | 31 | - `/` - Project-level configuration (linting rules, CI, docs, license) 32 | - `bin/` - Path to "binary" file, used as the entry point to the command (e.g. `awl` -> bin/index.js) 33 | - `fixtures/` - Files used during tests to simulate running the plugin inside Serverless Framework 34 | - `src/` - The source code and test specifications 35 | 36 | ## Installing 37 | 38 | ```shell 39 | # Install the dependencies & devDependencies 40 | npm install 41 | ``` 42 | 43 | ## Running Tests 44 | 45 | ```shell 46 | # Run unit tests 47 | npm test 48 | 49 | # Run unit tests in watch mode 50 | npm run test:watch 51 | 52 | # Run tests and see the coverage report 53 | npm run test:resport 54 | ``` 55 | 56 | ## Formatting your source code 57 | 58 | This project uses [eslint](https://eslint.org) and [prettier](https://prettier.io/) to format the source code. 59 | If the source code is not properly formatted, the CI will fail and the PR cannot be merged. 60 | 61 | You can automatically format your code by running: 62 | 63 | - `npm run lint`: format _all_ source code 64 | 65 | A better way is to set up your IDE to format the changed file on each file save. 66 | 67 | ### WebStorm / IntelliJ 68 | 69 | 1. Open `Preferences > Languages & Frameworks > JavaScript > Prettier` 70 | 1. Find the field named "Prettier Package" 71 | 1. Add `//packages/web-app/node_modules/prettier` 72 | 73 | ## Linting/Verifying the Source Code 74 | 75 | You can check that your code is properly formatted and adheres to coding style: 76 | 77 | ```shell 78 | # Check that the code is formatted and following the coding style: 79 | npm run verify 80 | 81 | # Fix any auto-fixable errors 82 | npm run lint 83 | ``` 84 | 85 | ## Semantic Release Setup 86 | 87 | This section is include for informational purposes only. 88 | 89 | This repo uses [semantic-release][semantic-release] to manage software versions and packaging. 90 | **There is a one-time setup-step required - WHICH HAS ALREADY BEEN DONE**, which creates a GitHub 91 | personal access token, an NPM token, and connects them to Travis CI. 92 | 93 | One time setup: 94 | ```shell script 95 | cd 96 | npx semantic-release-cli setup 97 | 98 | ? What is your npm registry? https://registry.npmjs.org/ 99 | ? What is your npm username? u_glow 100 | ? What is your npm password? [hidden] 101 | ? Provide a GitHub Personal Access Token (create a token at https://github.com/settings/tokens/new?scopes=repo) 102 | ? What CI are you using? Other (choose "Other" and the tokens are displayed for you manually add to your CI) 103 | 104 | ``` 105 | 106 |
107 | 108 | [contributing]: CONTRIBUTING.md 109 | [repo]: https://github.com/uglow/active-win-log 110 | [readme-usage]: README.md#usage 111 | [semantic-release]: https://semantic-release.gitbook.io/semantic-release/ 112 | -------------------------------------------------------------------------------- /fixtures/compressed.json: -------------------------------------------------------------------------------- 1 | {"Z"]},"Z"]},"Z"],"Z","Z","Z","Z"],"Z"]}},"Z"]},"Z"]},"Z"],"Z","Z","Z","Z"],"Z"]}},"Z","Z","Z","Z","Z","Z","Z"]},"Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"]},"Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"Z"]},"Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"]},"Z","Z","Z","Z"]},"Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"]},"Z"],"Z"]}},"2019-3-24 ": {"Sublime Text": {"awl.json": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"]},"Google Chrome": {"": ["Z","Z","Z"],"Process | Node.js v11.12.0 Documentation": ["Z"],"New Tab": ["Z"],"npm pack - Google Search": ["Z","Z","Z","Z","Z"],"How to make a beautiful, tiny npm package and publish it": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"npm-developers | npm Documentation": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"]},"WebStorm": {"active-win-log [/mydev/code/npm/active-win-log] - .../src/activeWinLog.js [active-win-log]": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"active-win-log [/mydev/code/npm/active-win-log] - .../src/runner.js [active-win-log]": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"active-win-log [/mydev/code/npm/active-win-log] - .../CONTRIBUTING.md [active-win-log]": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"active-win-log [/mydev/code/npm/active-win-log] - .../config/release/commitMessageConfig.js [active-win-log]": ["Z"],"active-win-log [/mydev/code/npm/active-win-log] - .../package.json [active-win-log]": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"active-win-log [/mydev/code/npm/active-win-log] - .../commitMessageConfig.js [active-win-log]": ["Z","Z","Z","Z","Z"],"": ["Z","Z"],"active-win-log [/mydev/code/npm/active-win-log] - .../.npmignore [active-win-log]": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"Delete": ["Z"],"active-win-log [/mydev/code/npm/active-win-log] - .../bin/index.js [active-win-log]": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"]},"Activity Monitor": {"Activity Monitor (All Processes)": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"],"": ["Z","Z"],"node (71241)": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"]},"loginwindow": {"": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"]},"Messages": {"": ["Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z","Z"]},"Finder": {".active-win-log": ["Z"],"active-win-log": ["Z","Z"]}}}} 2 | -------------------------------------------------------------------------------- /src/activeWinLog.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const { promisify } = require('util'); 6 | const statAsync = promisify(fs.stat); 7 | const mkDirAsync = promisify(fs.mkdir); 8 | const readFileAsync = promisify(fs.readFile); 9 | const writeFileAsync = promisify(fs.writeFile); 10 | const activeWin = require('active-win'); 11 | const userhome = require('userhome'); 12 | const LOG_FILE = 'awl.json'; 13 | const COMMANDS = { 14 | HELP: '-?', 15 | PRINT: '-l', 16 | QUIT: '-q', 17 | }; 18 | const WIN_MEASURE_INTERVAL = 5000; // Check for the active window every 5 seconds 19 | 20 | /** 21 | * ActiveWinLog - stores the name of the log file that is being used 22 | * @param {string[]} args - command line arguments 23 | * @param {string} cwd - current working directory (necessary for local devlogs) 24 | * @param {string} logFile - full path to the logfile to use 25 | * @constructor 26 | */ 27 | 28 | class ActiveWinLog { 29 | // Use a class because 30 | constructor({ logFile = path.join(userhome('.active-win-log'), LOG_FILE) } = {}) { 31 | this.logFile = logFile; 32 | } 33 | 34 | async init() { 35 | try { 36 | await statAsync(this.logFile); 37 | } catch (err) { 38 | // Create directory & file 39 | try { 40 | await mkDirAsync(path.dirname(this.logFile)); // This could fail if the directory exists, which is fine 41 | } catch (err2) { 42 | // ignore error here 43 | } 44 | this.setLogFileData({ pid: process.pid, stats: {} }); 45 | } 46 | } 47 | 48 | showHelp() { 49 | return [ 50 | '\nUsage: awl ', 51 | 'awl Start monitoring the active window', 52 | `awl ${COMMANDS.HELP} This help information`, 53 | `awl ${COMMANDS.PRINT} n Display statistics for the last "n" days in the log`, 54 | `awl ${COMMANDS.QUIT} Stop monitoring`, 55 | `Global log location: ${this.logFile}`, 56 | ].join('\n'); 57 | } 58 | 59 | async run() { 60 | // eslint-disable-next-line no-constant-condition 61 | while (true) { 62 | await sleep(WIN_MEASURE_INTERVAL); 63 | await this.recordActiveWin(); 64 | } 65 | } 66 | 67 | async recordActiveWin(eventDateTime = new Date().toLocaleString()) { 68 | let winInfo = null; 69 | 70 | try { 71 | winInfo = await activeWin(); 72 | } catch (err) { 73 | // no need to do anything, we will bail shortly 74 | } 75 | 76 | // If there are no active windows, don't log anything 77 | if (!winInfo) { 78 | return; 79 | } 80 | 81 | const logFileObj = await this.getLogFileData(); 82 | const eventDate = eventDateTime.substr(0, 10); // Just the date-part of the string 83 | 84 | // Add a record to the log file, grouped by day 85 | const dateKey = (logFileObj.stats[eventDate] = logFileObj.stats[eventDate] || {}); 86 | const appKey = (dateKey[winInfo.owner.name] = dateKey[winInfo.owner.name] || {}); 87 | const titleKey = (appKey[winInfo.title] = appKey[winInfo.title] || []); 88 | 89 | // Add a new value 90 | titleKey.push(eventDateTime); 91 | 92 | await this.setLogFileData(logFileObj); 93 | } 94 | 95 | async getStats({ lastNDays = 1 }) { 96 | const c = require('ansi-colors'); 97 | const logFileObj = await this.getLogFileData(); 98 | const dateKeys = Object.keys(logFileObj.stats); 99 | 100 | // Take the date from the end of the file (newest at the end), then process it oldest-first 101 | const keysToDisplay = dateKeys 102 | .reverse() 103 | .slice(0, lastNDays) 104 | .reverse(); 105 | 106 | const output = []; // Store the output as array of strings, for rendering how you wish. 107 | 108 | // This is not the most elegant algorithm or output, but it's good enough for my needs. 109 | keysToDisplay.forEach(day => { 110 | // Start bottom-up: get the total time from the app-windows, then group by app, then by day 111 | const windowTime = Object.keys(logFileObj.stats[day]).map(app => 112 | Object.keys(logFileObj.stats[day][app]).map(win => ({ 113 | name: win, 114 | time: logFileObj.stats[day][app][win].length * WIN_MEASURE_INTERVAL, // count time stamps 115 | })) 116 | ); 117 | 118 | const appTime = Object.keys(logFileObj.stats[day]).map((app, i) => ({ 119 | name: app, 120 | time: windowTime[i].reduce((acc, curr) => acc + curr.time, 0), // sum the time from the child windows 121 | })); 122 | 123 | const dayTime = { name: day, time: appTime.reduce((acc, curr) => acc + curr.time, 0) }; 124 | 125 | output.push(formatStatLine(dayTime, c.yellow.bold.underline, c.yellow.bold.underline)); 126 | appTime.forEach((app, i) => { 127 | output.push(formatStatLine(app, c.green, c.green.bold)); 128 | windowTime[i].forEach(win => output.push(formatStatLine(win, c.cyan, c.cyan, 2))); 129 | }); 130 | 131 | output.push(''); // line separating each day 132 | }); 133 | return output.join('\n'); 134 | } 135 | 136 | async killExistingProcess() { 137 | const logFileObj = await this.getLogFileData(); 138 | try { 139 | process.kill(logFileObj.pid, 'SIGHUP'); 140 | } catch (err) { 141 | // Probably no process to kill. Ignore 142 | } 143 | // Update the logFileData with this process's processId 144 | logFileObj.pid = process.pid; 145 | await this.setLogFileData(logFileObj); 146 | } 147 | 148 | async getLogFileData() { 149 | const logFile = await readFileAsync(this.logFile); 150 | return JSON.parse(logFile); 151 | } 152 | 153 | async setLogFileData(jsObj) { 154 | await writeFileAsync(this.logFile, JSON.stringify(jsObj, null, '\t')); 155 | } 156 | } 157 | 158 | function sleep(ms) { 159 | return new Promise(resolve => setTimeout(resolve, ms)); 160 | } 161 | 162 | function formatMillis(milliseconds) { 163 | const seconds = Math.round(milliseconds / 1000); 164 | const hours = Math.floor(seconds / 3600); 165 | const minutes = Math.floor((seconds - hours * 3600) / 60); 166 | const remainingSeconds = seconds - hours * 3600 - minutes * 60; 167 | 168 | return [ 169 | String(hours).padStart(2, '0'), 170 | String(minutes).padStart(2, '0'), 171 | String(remainingSeconds).padStart(2, '0'), 172 | ].join(':'); 173 | } 174 | 175 | function formatStatLine(nameTime, nameStyleFn, totalStyleFn, indent = 0, charLength = 50 - indent) { 176 | return `${' '.repeat(indent)}${nameStyleFn( 177 | (nameTime.name || '').substr(0, charLength).padEnd(charLength, ' ') + ' ' 178 | )}${totalStyleFn(formatMillis(nameTime.time))}`; 179 | } 180 | 181 | module.exports = { 182 | ActiveWinLog, 183 | COMMANDS, 184 | }; 185 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Welcome! This document explains how you can contribute to making this tool even better. 4 | 5 | # Getting Started 6 | 7 | ## Installation 8 | 9 | ``` 10 | git clone 11 | npm install -g commitizen 12 | npm install -g semantic-release-cli 13 | npm install 14 | ``` 15 | 16 | ## Directory Structure 17 | 18 | Code is organised into modules which contain one-or-more components. This a great way to ensure maintainable code by encapsulation of behavior logic. A component is basically a self contained app usually in a single file or a folder with each concern as a file: style, template, specs, e2e, and component class. Here's how it looks: 19 | ``` 20 | active-win-log/ 21 | ├──bin/ * The main "binary" (command line script) 22 | │ 23 | ├──fixtures/ * Test fixture files 24 | │ 25 | ├──src/ * Main source code 26 | │ 27 | ├──test-reports/ * Generated test reports 28 | │ 29 | ├──CONTRIBUTING.md * How to contribute to the project 30 | ├──README.md * This file 31 | ├──... * Other top-level config including testing, commit message conventions 32 | └──package.json * NPM package description file 33 | ``` 34 | 35 | 36 | # GitFlow Development Process 37 | 38 | This project uses the [GitHub Flow](https://guides.github.com/introduction/flow/index.html) workflow. 39 | 40 | ## Create a branch 41 | When you're working on a project, you're going to have a bunch of different features or ideas in progress at any given time – some of which are ready to go, and others which are not. Branching exists to help you manage this workflow. 42 | 43 | When you create a branch in your project, you're creating an environment where you can try out new ideas. Changes you make on a branch don't affect the `master` branch, so you're free to experiment and commit changes, safe in the knowledge that your branch won't be merged until it's ready to be reviewed by someone you're collaborating with. 44 | 45 | ### ProTip 46 | 47 | Branching is a core concept in Git, and the entire GitHub Flow is based upon it. There's only one rule: anything in the `master` branch is always deployable. 48 | 49 | Because of this, it's extremely important that your new branch is created off of `master` when working on a feature or a fix. Your branch name should be descriptive (e.g., `refactor-authentication`, `user-content-cache-key`, `make-retina-avatars`), so that others can see what is being worked on. 50 | 51 | ## Add commits 52 | Once your branch has been created, it's time to start making changes. Whenever you add, edit, or delete a file, you're making a commit, and adding them to your branch. This process of adding commits keeps track of your progress as you work on a feature branch. 53 | 54 | Commits also create a transparent history of your work that others can follow to understand what you've done and why. Each commit has an associated commit message, which is a description explaining why a particular change was made. Furthermore, each commit is considered a separate unit of change. This lets you roll back changes if a bug is found, or if you decide to head in a different direction. 55 | 56 | ### ProTip 57 | 58 | Commit messages are important, especially since Git tracks your changes and then displays them as commits once they're pushed to the server. By writing clear commit messages, you can make it easier for other people to follow along and provide feedback. 59 | 60 | ## Open a pull request 61 | 62 | Pull Requests initiate discussion about your commits. Because they're tightly integrated with the underlying Git repository, anyone can see exactly what changes would be merged if they accept your request. 63 | 64 | You can open a Pull Request at any point during the development process: when you have little or no code but want to share some screenshots or general ideas, when you're stuck and need help or advice, or when you're ready for someone to review your work. By using GitHub's @mention system in your Pull Request message, you can ask for feedback from specific people or teams, whether they're down the hall or ten time zones away. 65 | 66 | ### ProTip 67 | 68 | Pull Requests are useful for contributing to open source projects and for managing changes to shared repositories. If you're using a Fork & Pull Model, Pull Requests provide a way to notify project maintainers about the changes you'd like them to consider. If you're using a Shared Repository Model, Pull Requests help start code review and conversation about proposed changes before they're merged into the `master` branch. 69 | 70 | ## Discuss and review your code 71 | Once a Pull Request has been opened, the person or team reviewing your changes may have questions or comments. Perhaps the coding style doesn't match project guidelines, the change is missing unit tests, or maybe everything looks great and props are in order. Pull Requests are designed to encourage and capture this type of conversation. 72 | 73 | You can also continue to push to your branch in light of discussion and feedback about your commits. If someone comments that you forgot to do something or if there is a bug in the code, you can fix it in your branch and push up the change. GitHub will show your new commits and any additional feedback you may receive in the unified Pull Request view. 74 | 75 | ### ProTip 76 | 77 | Pull Request comments are written in Markdown, so you can embed images and emoji, use pre-formatted text blocks, and other lightweight formatting. 78 | 79 | ## Merge to `master` 80 | 81 | Once your PR has passed any the integration tests and received approval to merge, it is time to merge your code into the `master` branch. 82 | 83 | Once merged, Pull Requests preserve a record of the historical changes to your code. Because they're searchable, they let anyone go back in time to understand why and how a decision was made. 84 | 85 | ### ProTip 86 | 87 | By incorporating certain keywords into the text of your Pull Request, you can associate issues with code. When your Pull Request is merged, the related issues are also closed. For example, entering the phrase Closes #32 would close issue number 32 in the repository. For more information, check out our help article. 88 | 89 | 90 | ## Build Tasks 91 | 92 | Command | Description 93 | :------ | :---------- 94 |
npm start
| Runs the `./bin/index.js` file, which is the command line script 95 | 96 | 97 | ## Test Tasks 98 | 99 | Command | Description 100 | :------ | :---------- 101 |
npm test
| Alias for `npm run test:unit` task 102 |
npm run test:report
| Run instrumented unit tests then verify coverage meets defined thresholds 103 |
npm run test:unit
| Run unit tests once 104 |
npm run test:watch
| Run unit tests whenever JS source or tests change 105 | 106 | 107 | ## Verification (Linting) Tasks 108 | 109 | Command | Description 110 | :------ | :---------- 111 |
npm run verify
| Verify code style and syntax but does not fix it 112 |
npm run lint
| Verify code style and syntax and fix any errors that can be fixed automatically 113 | 114 | 115 | ## Commit Tasks 116 | 117 | Command | Description 118 | :------ | :---------- 119 |
git status
| Lists the current branch and the status of changed files 120 |
git log
| Displays the commit log (press Q to quit viewing) 121 |
git add .
| Stages all modified & untracked files, ready to be committed 122 |
git cz
| Commit changes to local repository using Commitizen
  • Asks questions about the change to generate a valid conventional commit message
  • Can be customised by modifying [config/release/commitMessageConfig.js](commitMessageConfig.js)
123 |
git push
| Push local repository changes to remote repository 124 | 125 | 126 | -------------------------------------------------------------------------------- /fixtures/uncompressed.json: -------------------------------------------------------------------------------- 1 | { 2 | "pid": 71241, 3 | "stats": { 4 | "2019-03-20": { 5 | "WebStorm From": { 6 | "active-win-log [/mydev/code/npm/active-win-log] - .../src/activeWinLog.js [active-win-log]": [ 7 | "2019-03-22T10:44:51.168Z" 8 | ] 9 | }, 10 | "Sublime From": { 11 | "awl.json": [ 12 | "2019-03-22T10:44:56.198Z" 13 | ] 14 | }, 15 | "Google From": { 16 | "table - npm": [ 17 | "2019-03-22T10:45:01.234Z" 18 | ], 19 | "Creating a real-world CLI app with Node": [ 20 | "2019-03-22T10:45:06.266Z", 21 | "2019-03-22T10:45:11.297Z", 22 | "2019-03-22T10:45:16.326Z", 23 | "2019-03-22T10:45:21.356Z" 24 | ], 25 | "": [ 26 | "2019-03-22T10:45:26.387Z" 27 | ] 28 | } 29 | }, 30 | "2019-03-22": { 31 | "WebStorm": { 32 | "active-win-log [/mydev/code/npm/active-win-log] - .../src/activeWinLog.js [active-win-log]": [ 33 | "2019-03-22T10:44:51.168Z" 34 | ] 35 | }, 36 | "Sublime Text": { 37 | "awl.json": [ 38 | "2019-03-22T10:44:56.198Z" 39 | ] 40 | }, 41 | "Google Chrome": { 42 | "table - npm": [ 43 | "2019-03-22T10:45:01.234Z" 44 | ], 45 | "Creating a real-world CLI app with Node": [ 46 | "2019-03-22T10:45:06.266Z", 47 | "2019-03-22T10:45:11.297Z", 48 | "2019-03-22T10:45:16.326Z", 49 | "2019-03-22T10:45:21.356Z" 50 | ], 51 | "": [ 52 | "2019-03-22T10:45:26.387Z" 53 | ] 54 | } 55 | }, 56 | "2019-03-23": { 57 | "Google Chrome": { 58 | "": [ 59 | "2019-03-23T09:23:06.622Z", 60 | "2019-03-23T21:04:27.507Z", 61 | "2019-03-23T21:04:32.540Z", 62 | "2019-03-23T21:04:37.573Z", 63 | "2019-03-23T21:04:42.602Z", 64 | "2019-03-23T21:04:47.630Z", 65 | "2019-03-23T21:04:52.663Z" 66 | ] 67 | }, 68 | "Sublime Text": { 69 | "awl.json": [ 70 | "2019-03-23T09:23:11.805Z", 71 | "2019-03-23T09:23:16.830Z", 72 | "2019-03-23T09:23:21.859Z", 73 | "2019-03-23T09:23:36.947Z", 74 | "2019-03-23T09:23:38.438Z", 75 | "2019-03-23T09:23:57.061Z", 76 | "2019-03-23T09:26:38.068Z", 77 | "2019-03-23T09:26:54.480Z", 78 | "2019-03-23T09:27:47.679Z", 79 | "2019-03-23T09:28:30.816Z", 80 | "2019-03-23T09:28:47.464Z", 81 | "2019-03-23T09:28:52.491Z", 82 | "2019-03-23T20:55:48.292Z", 83 | "2019-03-23T20:55:53.320Z", 84 | "2019-03-23T20:55:58.347Z", 85 | "2019-03-23T21:03:47.273Z", 86 | "2019-03-23T21:03:52.304Z", 87 | "2019-03-23T21:03:57.331Z", 88 | "2019-03-23T21:04:02.359Z", 89 | "2019-03-23T21:04:07.390Z", 90 | "2019-03-23T21:04:12.418Z", 91 | "2019-03-23T21:04:17.447Z", 92 | "2019-03-23T21:04:22.477Z" 93 | ] 94 | }, 95 | "WebStorm": { 96 | "active-win-log [/mydev/code/npm/active-win-log] - .../src/runner.js [active-win-log]": [ 97 | "2019-03-23T09:23:26.888Z", 98 | "2019-03-23T09:23:31.917Z", 99 | "2019-03-23T09:23:33.362Z", 100 | "2019-03-23T09:23:58.560Z", 101 | "2019-03-23T09:24:02.090Z", 102 | "2019-03-23T09:24:03.588Z", 103 | "2019-03-23T09:24:07.120Z", 104 | "2019-03-23T09:24:08.619Z", 105 | "2019-03-23T09:27:04.536Z", 106 | "2019-03-23T09:27:14.601Z", 107 | "2019-03-23T09:27:19.642Z", 108 | "2019-03-23T09:27:24.669Z", 109 | "2019-03-23T09:27:29.704Z", 110 | "2019-03-23T09:27:34.732Z", 111 | "2019-03-23T09:27:39.809Z", 112 | "2019-03-23T09:28:35.860Z", 113 | "2019-03-23T20:55:13.066Z", 114 | "2019-03-23T20:56:14.058Z", 115 | "2019-03-23T20:56:19.104Z", 116 | "2019-03-23T20:56:24.201Z", 117 | "2019-03-23T20:56:29.234Z", 118 | "2019-03-23T20:56:34.300Z", 119 | "2019-03-23T20:56:39.336Z", 120 | "2019-03-23T20:56:44.370Z", 121 | "2019-03-23T20:56:49.409Z", 122 | "2019-03-23T20:56:54.437Z", 123 | "2019-03-23T20:56:59.470Z", 124 | "2019-03-23T20:57:04.499Z", 125 | "2019-03-23T20:57:09.529Z", 126 | "2019-03-23T20:57:14.562Z", 127 | "2019-03-23T20:57:19.595Z", 128 | "2019-03-23T20:57:24.622Z", 129 | "2019-03-23T20:57:29.655Z", 130 | "2019-03-23T20:57:34.686Z", 131 | "2019-03-23T20:57:39.721Z", 132 | "2019-03-23T20:58:04.886Z", 133 | "2019-03-23T21:00:00.685Z", 134 | "2019-03-23T21:00:15.809Z", 135 | "2019-03-23T21:00:20.839Z", 136 | "2019-03-23T21:00:25.877Z", 137 | "2019-03-23T21:00:30.909Z", 138 | "2019-03-23T21:00:35.939Z", 139 | "2019-03-23T21:00:40.967Z", 140 | "2019-03-23T21:00:51.049Z", 141 | "2019-03-23T21:00:56.110Z", 142 | "2019-03-23T21:01:01.142Z", 143 | "2019-03-23T21:01:06.174Z", 144 | "2019-03-23T21:01:11.228Z", 145 | "2019-03-23T21:01:16.284Z", 146 | "2019-03-23T21:01:21.310Z", 147 | "2019-03-23T21:01:26.337Z", 148 | "2019-03-23T21:01:31.364Z", 149 | "2019-03-23T21:01:36.398Z", 150 | "2019-03-23T21:01:41.426Z", 151 | "2019-03-23T21:02:56.965Z", 152 | "2019-03-23T21:03:01.994Z", 153 | "2019-03-23T21:03:07.024Z", 154 | "2019-03-23T21:03:12.053Z", 155 | "2019-03-23T21:03:17.082Z", 156 | "2019-03-23T21:03:22.107Z", 157 | "2019-03-23T21:03:27.146Z", 158 | "2019-03-23T21:03:32.174Z", 159 | "2019-03-23T21:03:37.212Z", 160 | "2019-03-23T21:04:57.691Z", 161 | "2019-03-23T21:05:21.124Z", 162 | "2019-03-23T21:05:26.171Z", 163 | "2019-03-23T21:05:31.198Z", 164 | "2019-03-23T21:05:36.230Z", 165 | "2019-03-23T21:05:41.263Z", 166 | "2019-03-23T21:05:46.305Z", 167 | "2019-03-23T21:05:51.332Z", 168 | "2019-03-23T21:05:56.359Z", 169 | "2019-03-23T21:06:01.383Z", 170 | "2019-03-23T21:06:06.433Z", 171 | "2019-03-23T21:06:11.461Z", 172 | "2019-03-23T21:06:16.488Z", 173 | "2019-03-23T21:06:21.513Z", 174 | "2019-03-23T21:06:26.546Z", 175 | "2019-03-23T21:06:36.616Z", 176 | "2019-03-23T21:06:41.650Z", 177 | "2019-03-23T21:06:46.687Z", 178 | "2019-03-23T21:06:51.717Z", 179 | "2019-03-23T21:06:56.745Z", 180 | "2019-03-23T21:07:01.807Z", 181 | "2019-03-23T21:07:06.838Z", 182 | "2019-03-23T21:07:11.870Z", 183 | "2019-03-23T21:07:16.922Z", 184 | "2019-03-23T21:07:21.988Z", 185 | "2019-03-23T21:07:27.018Z", 186 | "2019-03-23T21:07:32.049Z", 187 | "2019-03-23T21:07:37.080Z", 188 | "2019-03-23T21:07:42.108Z", 189 | "2019-03-23T21:07:47.137Z", 190 | "2019-03-23T21:08:37.469Z", 191 | "2019-03-23T21:08:42.520Z", 192 | "2019-03-23T21:08:47.553Z", 193 | "2019-03-23T21:08:52.585Z", 194 | "2019-03-23T21:08:57.616Z", 195 | "2019-03-23T21:09:02.646Z", 196 | "2019-03-23T21:09:07.684Z", 197 | "2019-03-23T21:09:12.714Z", 198 | "2019-03-23T21:09:17.743Z" 199 | ], 200 | "active-win-log [/mydev/code/npm/active-win-log] - .../src/activeWinLog.js [active-win-log]": [ 201 | "2019-03-23T09:24:12.148Z", 202 | "2019-03-23T09:24:13.654Z", 203 | "2019-03-23T09:24:17.182Z", 204 | "2019-03-23T09:24:18.682Z", 205 | "2019-03-23T09:24:22.211Z", 206 | "2019-03-23T09:24:23.727Z", 207 | "2019-03-23T09:24:27.240Z", 208 | "2019-03-23T09:24:28.760Z", 209 | "2019-03-23T09:24:32.269Z", 210 | "2019-03-23T09:24:33.788Z", 211 | "2019-03-23T09:24:37.301Z", 212 | "2019-03-23T09:24:38.820Z", 213 | "2019-03-23T09:24:42.327Z", 214 | "2019-03-23T09:24:43.877Z", 215 | "2019-03-23T09:24:52.382Z", 216 | "2019-03-23T09:24:53.941Z", 217 | "2019-03-23T09:24:57.411Z", 218 | "2019-03-23T09:24:58.989Z", 219 | "2019-03-23T09:25:02.440Z", 220 | "2019-03-23T09:25:04.017Z", 221 | "2019-03-23T09:25:07.470Z", 222 | "2019-03-23T09:25:09.051Z", 223 | "2019-03-23T09:25:12.498Z", 224 | "2019-03-23T09:25:14.078Z", 225 | "2019-03-23T09:25:17.525Z", 226 | "2019-03-23T09:25:19.107Z", 227 | "2019-03-23T09:25:22.569Z", 228 | "2019-03-23T09:25:24.172Z", 229 | "2019-03-23T09:25:27.620Z", 230 | "2019-03-23T09:25:29.202Z", 231 | "2019-03-23T09:25:32.651Z", 232 | "2019-03-23T09:25:34.262Z", 233 | "2019-03-23T09:25:37.683Z", 234 | "2019-03-23T09:25:39.292Z", 235 | "2019-03-23T09:25:42.734Z", 236 | "2019-03-23T09:25:44.336Z", 237 | "2019-03-23T09:25:47.760Z", 238 | "2019-03-23T09:25:49.369Z", 239 | "2019-03-23T09:25:52.792Z", 240 | "2019-03-23T09:25:54.402Z", 241 | "2019-03-23T09:25:57.817Z", 242 | "2019-03-23T09:25:59.444Z", 243 | "2019-03-23T09:26:02.848Z", 244 | "2019-03-23T09:26:04.478Z", 245 | "2019-03-23T09:26:07.882Z", 246 | "2019-03-23T09:26:14.552Z", 247 | "2019-03-23T09:26:17.951Z", 248 | "2019-03-23T09:26:19.592Z", 249 | "2019-03-23T09:26:22.980Z", 250 | "2019-03-23T09:26:24.643Z", 251 | "2019-03-23T09:26:28.012Z", 252 | "2019-03-23T09:26:29.679Z", 253 | "2019-03-23T09:26:33.036Z", 254 | "2019-03-23T09:26:34.710Z", 255 | "2019-03-23T09:26:59.509Z", 256 | "2019-03-23T20:55:18.095Z", 257 | "2019-03-23T20:55:23.121Z", 258 | "2019-03-23T20:55:28.150Z", 259 | "2019-03-23T20:55:33.180Z", 260 | "2019-03-23T20:56:03.378Z", 261 | "2019-03-23T20:56:08.408Z", 262 | "2019-03-23T20:57:44.753Z", 263 | "2019-03-23T20:57:49.801Z", 264 | "2019-03-23T20:57:54.829Z", 265 | "2019-03-23T20:57:59.858Z", 266 | "2019-03-23T20:58:09.914Z", 267 | "2019-03-23T20:58:14.958Z", 268 | "2019-03-23T20:58:20.035Z", 269 | "2019-03-23T20:58:25.065Z", 270 | "2019-03-23T20:58:30.095Z", 271 | "2019-03-23T20:58:35.123Z", 272 | "2019-03-23T20:58:40.172Z", 273 | "2019-03-23T20:58:45.200Z", 274 | "2019-03-23T20:58:50.227Z", 275 | "2019-03-23T20:58:55.257Z", 276 | "2019-03-23T20:59:00.291Z", 277 | "2019-03-23T20:59:10.345Z", 278 | "2019-03-23T20:59:15.384Z", 279 | "2019-03-23T20:59:20.416Z", 280 | "2019-03-23T20:59:25.445Z", 281 | "2019-03-23T20:59:30.473Z", 282 | "2019-03-23T20:59:35.502Z", 283 | "2019-03-23T20:59:40.568Z", 284 | "2019-03-23T20:59:45.599Z", 285 | "2019-03-23T20:59:50.627Z", 286 | "2019-03-23T20:59:55.655Z", 287 | "2019-03-23T21:00:05.716Z", 288 | "2019-03-23T21:00:10.759Z", 289 | "2019-03-23T21:00:45.995Z", 290 | "2019-03-23T21:01:46.457Z", 291 | "2019-03-23T21:01:56.554Z", 292 | "2019-03-23T21:02:06.642Z", 293 | "2019-03-23T21:02:11.674Z", 294 | "2019-03-23T21:02:26.757Z", 295 | "2019-03-23T21:02:31.788Z", 296 | "2019-03-23T21:02:36.817Z", 297 | "2019-03-23T21:02:41.874Z", 298 | "2019-03-23T21:02:46.906Z", 299 | "2019-03-23T21:02:51.936Z", 300 | "2019-03-23T21:07:52.167Z", 301 | "2019-03-23T21:07:57.194Z", 302 | "2019-03-23T21:08:02.224Z", 303 | "2019-03-23T21:08:07.253Z", 304 | "2019-03-23T21:08:12.286Z", 305 | "2019-03-23T21:08:17.315Z", 306 | "2019-03-23T21:08:22.379Z", 307 | "2019-03-23T21:08:27.407Z", 308 | "2019-03-23T21:08:32.437Z" 309 | ], 310 | "": [ 311 | "2019-03-23T09:24:47.357Z", 312 | "2019-03-23T09:24:48.909Z", 313 | "2019-03-23T09:26:09.525Z", 314 | "2019-03-23T09:26:12.919Z", 315 | "2019-03-23T09:27:09.568Z", 316 | "2019-03-23T20:59:05.320Z", 317 | "2019-03-23T21:02:01.608Z", 318 | "2019-03-23T21:02:16.702Z", 319 | "2019-03-23T21:02:21.728Z", 320 | "2019-03-23T21:06:31.583Z" 321 | ], 322 | "Rename": [ 323 | "2019-03-23T21:01:51.526Z" 324 | ] 325 | }, 326 | "Activity Monitor": { 327 | "Activity Monitor (All Processes)": [ 328 | "2019-03-23T09:23:41.977Z", 329 | "2019-03-23T09:23:43.471Z", 330 | "2019-03-23T09:23:47.004Z", 331 | "2019-03-23T09:23:48.498Z", 332 | "2019-03-23T09:23:52.032Z", 333 | "2019-03-23T09:23:53.532Z", 334 | "2019-03-23T09:26:39.375Z", 335 | "2019-03-23T09:26:39.740Z", 336 | "2019-03-23T09:26:44.422Z", 337 | "2019-03-23T09:26:44.773Z", 338 | "2019-03-23T09:26:49.452Z", 339 | "2019-03-23T09:27:52.725Z", 340 | "2019-03-23T09:27:57.759Z", 341 | "2019-03-23T09:28:02.790Z", 342 | "2019-03-23T09:28:42.418Z" 343 | ] 344 | }, 345 | "Sourcetree": { 346 | "/mydev/code/npm/active-win-log (Git)": [ 347 | "2019-03-23T09:29:02.545Z", 348 | "2019-03-23T09:29:07.571Z", 349 | "2019-03-23T20:55:08.036Z", 350 | "2019-03-23T20:55:38.231Z" 351 | ] 352 | }, 353 | "loginwindow": { 354 | "": [ 355 | "2019-03-23T09:29:12.600Z", 356 | "2019-03-23T09:29:17.873Z", 357 | "2019-03-23T09:29:22.907Z", 358 | "2019-03-23T09:29:27.943Z", 359 | "2019-03-23T09:29:32.974Z", 360 | "2019-03-23T09:29:45.373Z", 361 | "2019-03-23T09:29:50.402Z", 362 | "2019-03-23T09:29:55.441Z", 363 | "2019-03-23T09:30:00.598Z", 364 | "2019-03-23T09:30:05.684Z", 365 | "2019-03-23T09:30:10.714Z", 366 | "2019-03-23T09:30:15.756Z", 367 | "2019-03-23T09:30:20.790Z", 368 | "2019-03-23T09:30:25.823Z", 369 | "2019-03-23T09:30:30.856Z", 370 | "2019-03-23T09:31:06.644Z", 371 | "2019-03-23T09:31:11.899Z", 372 | "2019-03-23T09:31:16.943Z", 373 | "2019-03-23T09:31:22.020Z", 374 | "2019-03-23T09:31:27.099Z", 375 | "2019-03-23T09:31:32.137Z", 376 | "2019-03-23T09:31:37.170Z", 377 | "2019-03-23T09:31:42.199Z", 378 | "2019-03-23T09:31:47.226Z", 379 | "2019-03-23T09:31:52.256Z", 380 | "2019-03-23T09:31:57.292Z", 381 | "2019-03-23T09:39:06.024Z", 382 | "2019-03-23T09:39:11.055Z", 383 | "2019-03-23T09:39:16.089Z", 384 | "2019-03-23T09:39:21.240Z", 385 | "2019-03-23T09:39:26.317Z", 386 | "2019-03-23T09:39:31.355Z", 387 | "2019-03-23T09:39:36.384Z", 388 | "2019-03-23T09:39:41.417Z", 389 | "2019-03-23T09:39:46.455Z", 390 | "2019-03-23T09:39:51.490Z", 391 | "2019-03-23T09:43:07.507Z", 392 | "2019-03-23T09:43:12.552Z", 393 | "2019-03-23T09:43:17.583Z", 394 | "2019-03-23T09:43:22.675Z", 395 | "2019-03-23T09:43:27.758Z", 396 | "2019-03-23T09:43:32.793Z", 397 | "2019-03-23T09:43:37.828Z", 398 | "2019-03-23T09:43:42.863Z", 399 | "2019-03-23T09:43:47.897Z", 400 | "2019-03-23T09:43:52.930Z", 401 | "2019-03-23T09:43:57.967Z", 402 | "2019-03-23T09:47:13.961Z", 403 | "2019-03-23T09:47:18.990Z", 404 | "2019-03-23T09:47:24.028Z", 405 | "2019-03-23T09:47:29.178Z", 406 | "2019-03-23T09:47:34.260Z", 407 | "2019-03-23T09:47:39.290Z", 408 | "2019-03-23T09:47:44.319Z", 409 | "2019-03-23T09:47:49.353Z", 410 | "2019-03-23T09:47:54.386Z", 411 | "2019-03-23T09:47:59.422Z", 412 | "2019-03-23T09:51:16.529Z", 413 | "2019-03-23T09:51:21.131Z", 414 | "2019-03-23T09:51:26.169Z", 415 | "2019-03-23T09:51:31.257Z", 416 | "2019-03-23T09:51:36.339Z", 417 | "2019-03-23T09:51:41.372Z", 418 | "2019-03-23T09:51:46.409Z", 419 | "2019-03-23T09:51:51.439Z", 420 | "2019-03-23T09:51:56.472Z", 421 | "2019-03-23T09:52:01.505Z", 422 | "2019-03-23T09:52:06.533Z", 423 | "2019-03-23T09:55:22.489Z", 424 | "2019-03-23T09:55:27.517Z", 425 | "2019-03-23T09:55:32.555Z", 426 | "2019-03-23T09:55:37.700Z", 427 | "2019-03-23T09:55:42.784Z", 428 | "2019-03-23T09:55:47.820Z", 429 | "2019-03-23T09:55:52.849Z", 430 | "2019-03-23T09:55:57.873Z", 431 | "2019-03-23T09:56:02.899Z", 432 | "2019-03-23T09:56:07.930Z", 433 | "2019-03-23T09:59:24.530Z", 434 | "2019-03-23T09:59:29.787Z", 435 | "2019-03-23T09:59:34.816Z", 436 | "2019-03-23T09:59:39.900Z", 437 | "2019-03-23T09:59:44.994Z", 438 | "2019-03-23T09:59:50.027Z", 439 | "2019-03-23T09:59:55.055Z", 440 | "2019-03-23T10:00:00.094Z", 441 | "2019-03-23T10:00:05.123Z", 442 | "2019-03-23T10:00:10.152Z", 443 | "2019-03-23T10:00:15.190Z", 444 | "2019-03-23T10:00:20.218Z", 445 | "2019-03-23T10:00:25.247Z", 446 | "2019-03-23T10:00:30.274Z", 447 | "2019-03-23T10:00:35.303Z", 448 | "2019-03-23T10:04:32.425Z", 449 | "2019-03-23T10:04:37.450Z", 450 | "2019-03-23T10:04:42.487Z", 451 | "2019-03-23T10:04:47.595Z", 452 | "2019-03-23T10:04:52.674Z", 453 | "2019-03-23T10:04:57.698Z", 454 | "2019-03-23T10:05:02.723Z", 455 | "2019-03-23T10:05:07.754Z", 456 | "2019-03-23T10:05:12.778Z", 457 | "2019-03-23T10:05:17.805Z", 458 | "2019-03-23T10:08:33.789Z", 459 | "2019-03-23T10:08:39.118Z", 460 | "2019-03-23T10:08:44.150Z", 461 | "2019-03-23T10:08:49.239Z", 462 | "2019-03-23T10:08:54.325Z", 463 | "2019-03-23T10:08:59.363Z", 464 | "2019-03-23T10:09:04.401Z", 465 | "2019-03-23T10:09:09.435Z", 466 | "2019-03-23T10:09:14.462Z", 467 | "2019-03-23T10:09:19.494Z", 468 | "2019-03-23T10:09:24.528Z", 469 | "2019-03-23T10:12:40.525Z", 470 | "2019-03-23T10:12:45.562Z", 471 | "2019-03-23T10:12:50.601Z", 472 | "2019-03-23T10:12:55.755Z", 473 | "2019-03-23T10:13:00.834Z", 474 | "2019-03-23T10:13:05.863Z", 475 | "2019-03-23T10:13:10.891Z", 476 | "2019-03-23T10:13:15.925Z", 477 | "2019-03-23T10:13:20.963Z", 478 | "2019-03-23T10:13:25.996Z", 479 | "2019-03-23T10:16:42.534Z", 480 | "2019-03-23T10:16:47.315Z", 481 | "2019-03-23T10:16:52.348Z", 482 | "2019-03-23T10:16:57.431Z", 483 | "2019-03-23T10:17:02.513Z", 484 | "2019-03-23T10:17:07.548Z", 485 | "2019-03-23T10:17:12.581Z", 486 | "2019-03-23T10:17:17.614Z", 487 | "2019-03-23T10:17:22.646Z", 488 | "2019-03-23T10:17:27.681Z", 489 | "2019-03-23T10:17:32.714Z", 490 | "2019-03-23T10:20:48.733Z", 491 | "2019-03-23T10:20:53.833Z", 492 | "2019-03-23T10:20:58.871Z", 493 | "2019-03-23T10:21:04.020Z", 494 | "2019-03-23T10:21:09.099Z", 495 | "2019-03-23T10:21:14.132Z", 496 | "2019-03-23T10:21:19.166Z", 497 | "2019-03-23T10:21:24.199Z", 498 | "2019-03-23T10:21:29.232Z", 499 | "2019-03-23T10:21:34.265Z", 500 | "2019-03-23T10:24:51.534Z", 501 | "2019-03-23T10:24:55.771Z", 502 | "2019-03-23T10:25:00.806Z", 503 | "2019-03-23T10:25:05.890Z", 504 | "2019-03-23T10:25:10.973Z", 505 | "2019-03-23T10:25:16.006Z", 506 | "2019-03-23T10:25:21.040Z", 507 | "2019-03-23T10:25:26.073Z", 508 | "2019-03-23T10:25:31.106Z", 509 | "2019-03-23T10:25:36.136Z", 510 | "2019-03-23T10:25:41.166Z", 511 | "2019-03-23T10:28:57.162Z", 512 | "2019-03-23T10:29:02.199Z", 513 | "2019-03-23T10:29:07.238Z", 514 | "2019-03-23T10:29:12.337Z", 515 | "2019-03-23T10:29:17.420Z", 516 | "2019-03-23T10:29:22.453Z", 517 | "2019-03-23T10:29:27.487Z", 518 | "2019-03-23T10:29:32.520Z", 519 | "2019-03-23T10:29:37.553Z", 520 | "2019-03-23T10:29:42.586Z", 521 | "2019-03-23T10:32:59.534Z", 522 | "2019-03-23T10:33:04.325Z", 523 | "2019-03-23T10:33:09.360Z", 524 | "2019-03-23T10:33:14.450Z", 525 | "2019-03-23T10:33:19.533Z", 526 | "2019-03-23T10:33:24.566Z", 527 | "2019-03-23T10:33:29.600Z", 528 | "2019-03-23T10:33:34.633Z", 529 | "2019-03-23T10:33:39.666Z", 530 | "2019-03-23T10:33:44.700Z", 531 | "2019-03-23T10:33:49.727Z", 532 | "2019-03-23T10:37:05.744Z", 533 | "2019-03-23T10:37:10.776Z", 534 | "2019-03-23T10:37:15.803Z", 535 | "2019-03-23T10:37:20.887Z", 536 | "2019-03-23T10:37:25.962Z", 537 | "2019-03-23T10:37:30.993Z", 538 | "2019-03-23T10:37:36.025Z", 539 | "2019-03-23T10:37:41.055Z", 540 | "2019-03-23T10:37:46.090Z", 541 | "2019-03-23T10:37:51.122Z", 542 | "2019-03-23T10:41:07.508Z", 543 | "2019-03-23T10:41:12.682Z", 544 | "2019-03-23T10:41:17.714Z", 545 | "2019-03-23T10:41:22.801Z", 546 | "2019-03-23T10:41:27.882Z", 547 | "2019-03-23T10:41:32.921Z", 548 | "2019-03-23T10:41:37.955Z", 549 | "2019-03-23T10:41:42.988Z", 550 | "2019-03-23T10:41:48.022Z", 551 | "2019-03-23T10:41:53.055Z", 552 | "2019-03-23T10:41:58.085Z", 553 | "2019-03-23T10:45:14.055Z", 554 | "2019-03-23T10:45:19.088Z", 555 | "2019-03-23T10:45:24.127Z", 556 | "2019-03-23T10:45:29.244Z", 557 | "2019-03-23T10:45:34.329Z", 558 | "2019-03-23T10:45:39.356Z", 559 | "2019-03-23T10:45:44.390Z", 560 | "2019-03-23T10:45:49.430Z", 561 | "2019-03-23T10:45:54.462Z", 562 | "2019-03-23T10:45:59.496Z", 563 | "2019-03-23T10:49:17.508Z", 564 | "2019-03-23T10:49:21.846Z", 565 | "2019-03-23T10:49:26.883Z", 566 | "2019-03-23T10:49:31.962Z", 567 | "2019-03-23T10:49:37.045Z", 568 | "2019-03-23T10:49:42.080Z", 569 | "2019-03-23T10:49:47.113Z", 570 | "2019-03-23T10:49:52.152Z", 571 | "2019-03-23T10:49:57.182Z", 572 | "2019-03-23T10:50:02.212Z", 573 | "2019-03-23T10:50:07.252Z", 574 | "2019-03-23T11:13:23.080Z", 575 | "2019-03-23T11:13:28.119Z", 576 | "2019-03-23T11:13:33.159Z", 577 | "2019-03-23T11:13:38.298Z", 578 | "2019-03-23T11:13:43.382Z", 579 | "2019-03-23T11:13:48.415Z", 580 | "2019-03-23T11:13:53.444Z", 581 | "2019-03-23T11:13:58.471Z", 582 | "2019-03-23T11:14:03.501Z", 583 | "2019-03-23T11:14:08.526Z", 584 | "2019-03-23T11:50:07.509Z", 585 | "2019-03-23T11:50:12.131Z", 586 | "2019-03-23T11:50:17.164Z", 587 | "2019-03-23T11:50:22.253Z", 588 | "2019-03-23T11:50:27.342Z", 589 | "2019-03-23T11:50:32.367Z", 590 | "2019-03-23T11:50:37.394Z", 591 | "2019-03-23T11:50:42.422Z", 592 | "2019-03-23T11:50:47.450Z", 593 | "2019-03-23T11:50:52.478Z", 594 | "2019-03-23T11:50:57.506Z", 595 | "2019-03-23T11:51:02.533Z", 596 | "2019-03-23T11:51:07.560Z", 597 | "2019-03-23T11:51:12.592Z", 598 | "2019-03-23T11:51:17.617Z", 599 | "2019-03-23T12:39:44.539Z", 600 | "2019-03-23T12:39:48.582Z", 601 | "2019-03-23T12:39:53.617Z", 602 | "2019-03-23T12:39:58.706Z", 603 | "2019-03-23T12:40:03.785Z", 604 | "2019-03-23T12:40:08.808Z", 605 | "2019-03-23T12:40:13.835Z", 606 | "2019-03-23T12:40:18.859Z", 607 | "2019-03-23T12:40:23.889Z", 608 | "2019-03-23T12:40:28.922Z", 609 | "2019-03-23T13:45:42.684Z", 610 | "2019-03-23T13:45:47.939Z", 611 | "2019-03-23T13:45:52.977Z", 612 | "2019-03-23T13:45:58.056Z", 613 | "2019-03-23T13:46:03.137Z", 614 | "2019-03-23T13:46:08.172Z", 615 | "2019-03-23T13:46:13.205Z", 616 | "2019-03-23T13:46:18.232Z", 617 | "2019-03-23T13:46:23.266Z", 618 | "2019-03-23T13:46:28.300Z", 619 | "2019-03-23T13:46:33.332Z", 620 | "2019-03-23T13:59:26.029Z", 621 | "2019-03-23T13:59:31.065Z", 622 | "2019-03-23T13:59:36.105Z", 623 | "2019-03-23T13:59:41.251Z", 624 | "2019-03-23T13:59:46.335Z", 625 | "2019-03-23T13:59:51.368Z", 626 | "2019-03-23T13:59:56.404Z", 627 | "2019-03-23T14:00:01.434Z", 628 | "2019-03-23T14:00:06.468Z", 629 | "2019-03-23T14:00:11.501Z", 630 | "2019-03-23T15:02:07.505Z", 631 | "2019-03-23T15:02:13.079Z", 632 | "2019-03-23T15:02:18.113Z", 633 | "2019-03-23T15:02:23.202Z", 634 | "2019-03-23T15:02:28.351Z", 635 | "2019-03-23T15:02:33.386Z", 636 | "2019-03-23T15:02:38.416Z", 637 | "2019-03-23T15:02:43.454Z", 638 | "2019-03-23T15:02:48.487Z", 639 | "2019-03-23T15:02:53.520Z", 640 | "2019-03-23T15:02:58.554Z", 641 | "2019-03-23T15:34:43.198Z", 642 | "2019-03-23T15:34:48.227Z", 643 | "2019-03-23T15:34:53.265Z", 644 | "2019-03-23T15:34:58.360Z", 645 | "2019-03-23T15:35:03.443Z", 646 | "2019-03-23T15:35:08.476Z", 647 | "2019-03-23T15:35:13.510Z", 648 | "2019-03-23T15:35:18.543Z", 649 | "2019-03-23T15:35:23.576Z", 650 | "2019-03-23T15:35:28.609Z", 651 | "2019-03-23T16:02:11.508Z", 652 | "2019-03-23T16:02:16.552Z", 653 | "2019-03-23T16:02:21.500Z", 654 | "2019-03-23T16:02:26.582Z", 655 | "2019-03-23T16:02:31.667Z", 656 | "2019-03-23T16:02:36.708Z", 657 | "2019-03-23T16:02:41.759Z", 658 | "2019-03-23T16:02:46.792Z", 659 | "2019-03-23T16:02:51.831Z", 660 | "2019-03-23T16:02:56.866Z", 661 | "2019-03-23T16:03:01.901Z", 662 | "2019-03-23T16:06:15.649Z", 663 | "2019-03-23T16:06:19.839Z", 664 | "2019-03-23T16:06:24.868Z", 665 | "2019-03-23T16:06:29.952Z", 666 | "2019-03-23T16:06:35.041Z", 667 | "2019-03-23T16:06:40.076Z", 668 | "2019-03-23T16:06:45.110Z", 669 | "2019-03-23T16:06:50.143Z", 670 | "2019-03-23T16:06:55.176Z", 671 | "2019-03-23T16:07:00.210Z", 672 | "2019-03-23T16:07:05.237Z", 673 | "2019-03-23T16:57:02.453Z", 674 | "2019-03-23T16:57:07.480Z", 675 | "2019-03-23T16:57:12.517Z", 676 | "2019-03-23T16:57:17.646Z", 677 | "2019-03-23T16:57:22.729Z", 678 | "2019-03-23T16:57:27.763Z", 679 | "2019-03-23T16:57:32.796Z", 680 | "2019-03-23T16:57:37.829Z", 681 | "2019-03-23T16:57:42.862Z", 682 | "2019-03-23T16:57:47.896Z", 683 | "2019-03-23T17:12:04.531Z", 684 | "2019-03-23T17:12:09.386Z", 685 | "2019-03-23T17:12:14.416Z", 686 | "2019-03-23T17:12:19.507Z", 687 | "2019-03-23T17:12:24.642Z", 688 | "2019-03-23T17:12:29.674Z", 689 | "2019-03-23T17:12:34.708Z", 690 | "2019-03-23T17:12:39.739Z", 691 | "2019-03-23T17:12:44.769Z", 692 | "2019-03-23T17:12:49.802Z", 693 | "2019-03-23T17:12:54.837Z", 694 | "2019-03-23T18:44:22.469Z", 695 | "2019-03-23T18:44:27.508Z", 696 | "2019-03-23T18:44:32.547Z", 697 | "2019-03-23T18:44:37.642Z", 698 | "2019-03-23T18:44:42.726Z", 699 | "2019-03-23T18:44:47.757Z", 700 | "2019-03-23T18:44:52.786Z", 701 | "2019-03-23T18:44:57.820Z", 702 | "2019-03-23T18:45:02.853Z", 703 | "2019-03-23T18:45:07.886Z", 704 | "2019-03-23T19:30:36.534Z", 705 | "2019-03-23T19:30:42.502Z", 706 | "2019-03-23T19:30:47.536Z", 707 | "2019-03-23T19:30:52.620Z", 708 | "2019-03-23T19:30:57.702Z", 709 | "2019-03-23T19:31:02.735Z", 710 | "2019-03-23T19:31:07.769Z", 711 | "2019-03-23T19:31:12.802Z", 712 | "2019-03-23T19:31:17.835Z", 713 | "2019-03-23T19:31:22.869Z", 714 | "2019-03-23T19:31:27.902Z", 715 | "2019-03-23T19:34:43.726Z", 716 | "2019-03-23T19:34:49.025Z", 717 | "2019-03-23T19:34:54.063Z", 718 | "2019-03-23T19:34:59.170Z", 719 | "2019-03-23T19:35:04.258Z", 720 | "2019-03-23T19:35:09.288Z", 721 | "2019-03-23T19:35:14.326Z", 722 | "2019-03-23T19:35:19.359Z", 723 | "2019-03-23T19:35:24.393Z", 724 | "2019-03-23T19:35:29.425Z", 725 | "2019-03-23T19:38:46.534Z", 726 | "2019-03-23T19:38:51.369Z", 727 | "2019-03-23T19:38:56.403Z", 728 | "2019-03-23T19:39:01.490Z", 729 | "2019-03-23T19:39:06.570Z", 730 | "2019-03-23T19:39:11.608Z", 731 | "2019-03-23T19:39:16.648Z", 732 | "2019-03-23T19:39:21.680Z", 733 | "2019-03-23T19:39:26.714Z", 734 | "2019-03-23T19:39:31.747Z", 735 | "2019-03-23T19:39:36.780Z", 736 | "2019-03-23T19:42:53.737Z", 737 | "2019-03-23T19:42:58.002Z", 738 | "2019-03-23T19:43:03.041Z", 739 | "2019-03-23T19:43:08.186Z", 740 | "2019-03-23T19:43:13.269Z", 741 | "2019-03-23T19:43:18.302Z", 742 | "2019-03-23T19:43:23.336Z", 743 | "2019-03-23T19:43:28.369Z", 744 | "2019-03-23T19:43:33.402Z", 745 | "2019-03-23T19:43:38.435Z", 746 | "2019-03-23T19:46:55.535Z", 747 | "2019-03-23T19:47:00.378Z", 748 | "2019-03-23T19:47:05.404Z", 749 | "2019-03-23T19:47:10.490Z", 750 | "2019-03-23T19:47:15.610Z", 751 | "2019-03-23T19:47:20.642Z", 752 | "2019-03-23T19:47:25.680Z", 753 | "2019-03-23T19:47:30.713Z", 754 | "2019-03-23T19:47:35.746Z", 755 | "2019-03-23T19:47:40.779Z", 756 | "2019-03-23T19:47:45.812Z", 757 | "2019-03-23T19:53:06.777Z", 758 | "2019-03-23T19:53:12.147Z", 759 | "2019-03-23T19:53:17.178Z", 760 | "2019-03-23T19:53:22.258Z", 761 | "2019-03-23T19:53:27.343Z", 762 | "2019-03-23T19:53:32.376Z", 763 | "2019-03-23T19:53:37.411Z", 764 | "2019-03-23T19:53:42.447Z", 765 | "2019-03-23T19:53:47.478Z", 766 | "2019-03-23T19:53:52.511Z", 767 | "2019-03-23T19:57:09.520Z", 768 | "2019-03-23T19:57:14.347Z", 769 | "2019-03-23T19:57:19.374Z", 770 | "2019-03-23T19:57:24.464Z", 771 | "2019-03-23T19:57:29.552Z", 772 | "2019-03-23T19:57:34.586Z", 773 | "2019-03-23T19:57:39.620Z", 774 | "2019-03-23T19:57:44.653Z", 775 | "2019-03-23T19:57:49.686Z", 776 | "2019-03-23T19:57:54.720Z", 777 | "2019-03-23T19:57:59.753Z", 778 | "2019-03-23T20:01:15.328Z", 779 | "2019-03-23T20:01:20.361Z", 780 | "2019-03-23T20:01:25.399Z", 781 | "2019-03-23T20:01:30.553Z", 782 | "2019-03-23T20:01:35.631Z", 783 | "2019-03-23T20:01:40.660Z", 784 | "2019-03-23T20:01:45.691Z", 785 | "2019-03-23T20:01:50.728Z", 786 | "2019-03-23T20:01:55.766Z", 787 | "2019-03-23T20:02:00.800Z", 788 | "2019-03-23T20:05:17.519Z", 789 | "2019-03-23T20:05:21.755Z", 790 | "2019-03-23T20:05:26.787Z", 791 | "2019-03-23T20:05:31.878Z", 792 | "2019-03-23T20:05:37.011Z", 793 | "2019-03-23T20:05:42.044Z", 794 | "2019-03-23T20:05:47.077Z", 795 | "2019-03-23T20:05:52.110Z", 796 | "2019-03-23T20:05:57.144Z", 797 | "2019-03-23T20:06:02.177Z", 798 | "2019-03-23T20:06:07.210Z", 799 | "2019-03-23T20:09:22.758Z", 800 | "2019-03-23T20:09:28.626Z", 801 | "2019-03-23T20:09:33.661Z", 802 | "2019-03-23T20:09:38.749Z", 803 | "2019-03-23T20:09:43.832Z", 804 | "2019-03-23T20:09:48.870Z", 805 | "2019-03-23T20:09:53.899Z", 806 | "2019-03-23T20:09:58.932Z", 807 | "2019-03-23T20:10:03.959Z", 808 | "2019-03-23T20:10:08.992Z", 809 | "2019-03-23T20:13:26.520Z", 810 | "2019-03-23T20:13:31.441Z", 811 | "2019-03-23T20:13:36.474Z", 812 | "2019-03-23T20:13:41.562Z", 813 | "2019-03-23T20:13:46.707Z", 814 | "2019-03-23T20:13:51.741Z", 815 | "2019-03-23T20:13:56.774Z", 816 | "2019-03-23T20:14:01.810Z", 817 | "2019-03-23T20:14:06.841Z", 818 | "2019-03-23T20:14:11.874Z", 819 | "2019-03-23T20:14:16.905Z", 820 | "2019-03-23T20:17:32.778Z", 821 | "2019-03-23T20:17:38.328Z", 822 | "2019-03-23T20:17:43.358Z", 823 | "2019-03-23T20:17:48.443Z", 824 | "2019-03-23T20:17:53.533Z", 825 | "2019-03-23T20:17:58.562Z", 826 | "2019-03-23T20:18:03.598Z", 827 | "2019-03-23T20:18:08.633Z", 828 | "2019-03-23T20:18:13.666Z", 829 | "2019-03-23T20:18:18.693Z", 830 | "2019-03-23T20:21:35.520Z", 831 | "2019-03-23T20:21:40.570Z", 832 | "2019-03-23T20:21:45.616Z", 833 | "2019-03-23T20:21:50.712Z", 834 | "2019-03-23T20:21:55.796Z", 835 | "2019-03-23T20:22:00.839Z", 836 | "2019-03-23T20:22:05.875Z", 837 | "2019-03-23T20:22:10.910Z", 838 | "2019-03-23T20:22:15.945Z", 839 | "2019-03-23T20:22:20.980Z", 840 | "2019-03-23T20:22:26.014Z", 841 | "2019-03-23T20:42:34.191Z", 842 | "2019-03-23T20:42:39.224Z", 843 | "2019-03-23T20:42:44.263Z", 844 | "2019-03-23T20:42:49.410Z", 845 | "2019-03-23T20:42:54.491Z", 846 | "2019-03-23T20:42:59.519Z", 847 | "2019-03-23T20:43:04.547Z", 848 | "2019-03-23T20:43:09.576Z", 849 | "2019-03-23T20:43:14.614Z", 850 | "2019-03-23T20:43:19.647Z", 851 | "2019-03-23T20:45:31.567Z", 852 | "2019-03-23T20:45:35.837Z", 853 | "2019-03-23T20:45:40.866Z", 854 | "2019-03-23T20:45:45.952Z", 855 | "2019-03-23T20:54:57.963Z", 856 | "2019-03-23T20:55:03.006Z" 857 | ] 858 | }, 859 | "Finder": { 860 | "coverage": [ 861 | "2019-03-23T20:55:43.264Z" 862 | ], 863 | ".active-win-log": [ 864 | "2019-03-23T21:03:42.241Z" 865 | ] 866 | } 867 | }, 868 | "2019-3-24 ": { 869 | "Sublime Text": { 870 | "awl.json": [ 871 | "2019-3-24 08:32:27", 872 | "2019-3-24 08:32:32", 873 | "2019-3-24 08:33:02", 874 | "2019-3-24 08:33:07", 875 | "2019-3-24 08:33:12", 876 | "2019-3-24 08:36:03", 877 | "2019-3-24 08:36:13", 878 | "2019-3-24 08:36:18", 879 | "2019-3-24 08:41:05", 880 | "2019-3-24 09:12:12", 881 | "2019-3-24 09:16:08" 882 | ] 883 | }, 884 | "Google Chrome": { 885 | "": [ 886 | "2019-3-24 08:32:37", 887 | "2019-3-24 08:32:47", 888 | "2019-3-24 08:32:52" 889 | ], 890 | "Process | Node.js v11.12.0 Documentation": [ 891 | "2019-3-24 08:32:57" 892 | ], 893 | "New Tab": [ 894 | "2019-3-24 08:47:58" 895 | ], 896 | "npm pack - Google Search": [ 897 | "2019-3-24 08:48:03", 898 | "2019-3-24 08:48:08", 899 | "2019-3-24 08:48:13", 900 | "2019-3-24 08:49:34", 901 | "2019-3-24 08:49:39" 902 | ], 903 | "How to make a beautiful, tiny npm package and publish it": [ 904 | "2019-3-24 08:48:18", 905 | "2019-3-24 08:48:23", 906 | "2019-3-24 08:48:28", 907 | "2019-3-24 08:48:33", 908 | "2019-3-24 08:48:38", 909 | "2019-3-24 08:48:44", 910 | "2019-3-24 08:48:49", 911 | "2019-3-24 08:49:04", 912 | "2019-3-24 08:49:09", 913 | "2019-3-24 08:49:14", 914 | "2019-3-24 08:49:19", 915 | "2019-3-24 08:49:24", 916 | "2019-3-24 08:49:29" 917 | ], 918 | "npm-developers | npm Documentation": [ 919 | "2019-3-24 08:49:44", 920 | "2019-3-24 08:50:34", 921 | "2019-3-24 08:50:39", 922 | "2019-3-24 08:50:49", 923 | "2019-3-24 08:50:54", 924 | "2019-3-24 08:50:59", 925 | "2019-3-24 08:51:04", 926 | "2019-3-24 08:51:55", 927 | "2019-3-24 08:52:00", 928 | "2019-3-24 08:52:05", 929 | "2019-3-24 08:52:10", 930 | "2019-3-24 08:53:56", 931 | "2019-3-24 08:54:01", 932 | "2019-3-24 08:54:06", 933 | "2019-3-24 09:09:57", 934 | "2019-3-24 09:10:02", 935 | "2019-3-24 09:10:07", 936 | "2019-3-24 09:10:12", 937 | "2019-3-24 09:10:17", 938 | "2019-3-24 09:10:32" 939 | ] 940 | }, 941 | "WebStorm": { 942 | "active-win-log [/mydev/code/npm/active-win-log] - .../src/activeWinLog.js [active-win-log]": [ 943 | "2019-3-24 08:32:42", 944 | "2019-3-24 08:33:17", 945 | "2019-3-24 09:13:22", 946 | "2019-3-24 09:13:27", 947 | "2019-3-24 09:13:32", 948 | "2019-3-24 09:13:37", 949 | "2019-3-24 09:13:43", 950 | "2019-3-24 09:13:48", 951 | "2019-3-24 09:13:53", 952 | "2019-3-24 09:13:58", 953 | "2019-3-24 09:14:03" 954 | ], 955 | "active-win-log [/mydev/code/npm/active-win-log] - .../src/runner.js [active-win-log]": [ 956 | "2019-3-24 08:35:41", 957 | "2019-3-24 08:36:08", 958 | "2019-3-24 08:36:23", 959 | "2019-3-24 08:36:28", 960 | "2019-3-24 08:36:33", 961 | "2019-3-24 08:36:38", 962 | "2019-3-24 08:36:43", 963 | "2019-3-24 08:36:48", 964 | "2019-3-24 08:36:53", 965 | "2019-3-24 08:58:17", 966 | "2019-3-24 08:58:23", 967 | "2019-3-24 08:58:28", 968 | "2019-3-24 08:58:33", 969 | "2019-3-24 08:58:38", 970 | "2019-3-24 08:58:43", 971 | "2019-3-24 08:58:48", 972 | "2019-3-24 08:58:53", 973 | "2019-3-24 08:58:58", 974 | "2019-3-24 08:59:03", 975 | "2019-3-24 08:59:08", 976 | "2019-3-24 08:59:13", 977 | "2019-3-24 08:59:18", 978 | "2019-3-24 08:59:23", 979 | "2019-3-24 08:59:28", 980 | "2019-3-24 09:11:27", 981 | "2019-3-24 09:11:42", 982 | "2019-3-24 09:13:17" 983 | ], 984 | "active-win-log [/mydev/code/npm/active-win-log] - .../CONTRIBUTING.md [active-win-log]": [ 985 | "2019-3-24 08:36:58", 986 | "2019-3-24 08:37:03", 987 | "2019-3-24 08:37:13", 988 | "2019-3-24 08:37:18", 989 | "2019-3-24 08:37:23", 990 | "2019-3-24 08:37:28", 991 | "2019-3-24 08:37:33", 992 | "2019-3-24 08:37:39", 993 | "2019-3-24 08:37:44", 994 | "2019-3-24 08:37:49", 995 | "2019-3-24 08:37:54", 996 | "2019-3-24 08:37:59", 997 | "2019-3-24 08:38:04", 998 | "2019-3-24 08:38:09", 999 | "2019-3-24 08:38:14", 1000 | "2019-3-24 08:38:19", 1001 | "2019-3-24 08:39:04", 1002 | "2019-3-24 08:39:09", 1003 | "2019-3-24 08:39:14", 1004 | "2019-3-24 08:39:19", 1005 | "2019-3-24 08:39:24", 1006 | "2019-3-24 08:39:29", 1007 | "2019-3-24 08:39:34", 1008 | "2019-3-24 08:39:40", 1009 | "2019-3-24 08:39:45", 1010 | "2019-3-24 08:39:50", 1011 | "2019-3-24 08:39:55", 1012 | "2019-3-24 08:40:00", 1013 | "2019-3-24 08:40:05", 1014 | "2019-3-24 08:40:10", 1015 | "2019-3-24 08:40:15", 1016 | "2019-3-24 08:40:20", 1017 | "2019-3-24 08:40:25", 1018 | "2019-3-24 08:40:30", 1019 | "2019-3-24 08:40:35", 1020 | "2019-3-24 08:40:40", 1021 | "2019-3-24 08:40:45", 1022 | "2019-3-24 08:40:50", 1023 | "2019-3-24 08:41:00", 1024 | "2019-3-24 08:41:25", 1025 | "2019-3-24 08:41:41", 1026 | "2019-3-24 08:41:46", 1027 | "2019-3-24 08:41:51", 1028 | "2019-3-24 08:41:56", 1029 | "2019-3-24 08:42:01", 1030 | "2019-3-24 08:42:06", 1031 | "2019-3-24 08:42:11", 1032 | "2019-3-24 08:42:16", 1033 | "2019-3-24 08:42:21", 1034 | "2019-3-24 08:42:26", 1035 | "2019-3-24 08:42:31", 1036 | "2019-3-24 08:42:41", 1037 | "2019-3-24 08:42:46", 1038 | "2019-3-24 08:42:51", 1039 | "2019-3-24 08:42:56", 1040 | "2019-3-24 08:43:01", 1041 | "2019-3-24 08:43:06", 1042 | "2019-3-24 08:43:11", 1043 | "2019-3-24 08:43:16", 1044 | "2019-3-24 08:43:26", 1045 | "2019-3-24 08:43:31", 1046 | "2019-3-24 08:43:36", 1047 | "2019-3-24 08:43:41", 1048 | "2019-3-24 08:43:47", 1049 | "2019-3-24 08:43:52", 1050 | "2019-3-24 08:43:57", 1051 | "2019-3-24 08:44:02", 1052 | "2019-3-24 08:44:07", 1053 | "2019-3-24 08:44:12", 1054 | "2019-3-24 08:44:17", 1055 | "2019-3-24 08:44:22", 1056 | "2019-3-24 08:44:27", 1057 | "2019-3-24 08:44:32", 1058 | "2019-3-24 08:44:37", 1059 | "2019-3-24 08:44:42", 1060 | "2019-3-24 08:44:47", 1061 | "2019-3-24 08:44:52", 1062 | "2019-3-24 08:44:57", 1063 | "2019-3-24 08:45:02", 1064 | "2019-3-24 08:45:07", 1065 | "2019-3-24 08:45:12", 1066 | "2019-3-24 08:45:17", 1067 | "2019-3-24 08:45:22", 1068 | "2019-3-24 08:45:27", 1069 | "2019-3-24 08:45:32", 1070 | "2019-3-24 08:45:37", 1071 | "2019-3-24 08:45:42", 1072 | "2019-3-24 08:45:47", 1073 | "2019-3-24 08:45:52", 1074 | "2019-3-24 08:45:57", 1075 | "2019-3-24 08:46:02", 1076 | "2019-3-24 08:46:07", 1077 | "2019-3-24 08:46:12", 1078 | "2019-3-24 08:46:18", 1079 | "2019-3-24 08:46:23", 1080 | "2019-3-24 08:46:28", 1081 | "2019-3-24 08:46:33", 1082 | "2019-3-24 08:46:38", 1083 | "2019-3-24 08:46:43", 1084 | "2019-3-24 08:46:48", 1085 | "2019-3-24 08:46:53", 1086 | "2019-3-24 08:46:58", 1087 | "2019-3-24 08:47:03", 1088 | "2019-3-24 08:47:08", 1089 | "2019-3-24 08:47:13", 1090 | "2019-3-24 08:47:18", 1091 | "2019-3-24 08:47:23", 1092 | "2019-3-24 08:47:28", 1093 | "2019-3-24 08:55:06" 1094 | ], 1095 | "active-win-log [/mydev/code/npm/active-win-log] - .../config/release/commitMessageConfig.js [active-win-log]": [ 1096 | "2019-3-24 08:38:24" 1097 | ], 1098 | "active-win-log [/mydev/code/npm/active-win-log] - .../package.json [active-win-log]": [ 1099 | "2019-3-24 08:38:29", 1100 | "2019-3-24 08:38:34", 1101 | "2019-3-24 08:41:30", 1102 | "2019-3-24 08:41:36", 1103 | "2019-3-24 08:43:21", 1104 | "2019-3-24 08:54:16", 1105 | "2019-3-24 08:54:21", 1106 | "2019-3-24 08:54:26", 1107 | "2019-3-24 08:54:31", 1108 | "2019-3-24 08:54:36", 1109 | "2019-3-24 08:54:41", 1110 | "2019-3-24 08:54:46", 1111 | "2019-3-24 08:54:51", 1112 | "2019-3-24 08:54:56", 1113 | "2019-3-24 08:55:11", 1114 | "2019-3-24 08:55:16", 1115 | "2019-3-24 08:55:21", 1116 | "2019-3-24 08:55:26", 1117 | "2019-3-24 08:55:31", 1118 | "2019-3-24 08:55:36", 1119 | "2019-3-24 08:55:41", 1120 | "2019-3-24 08:55:46", 1121 | "2019-3-24 08:55:51", 1122 | "2019-3-24 08:55:56", 1123 | "2019-3-24 08:56:02", 1124 | "2019-3-24 08:56:37", 1125 | "2019-3-24 08:56:42", 1126 | "2019-3-24 08:56:47", 1127 | "2019-3-24 08:56:52", 1128 | "2019-3-24 08:56:57", 1129 | "2019-3-24 08:57:27", 1130 | "2019-3-24 08:57:32", 1131 | "2019-3-24 08:57:47", 1132 | "2019-3-24 08:57:52", 1133 | "2019-3-24 09:00:23", 1134 | "2019-3-24 09:00:28", 1135 | "2019-3-24 09:00:33", 1136 | "2019-3-24 09:00:38", 1137 | "2019-3-24 09:00:44", 1138 | "2019-3-24 09:00:49", 1139 | "2019-3-24 09:10:22", 1140 | "2019-3-24 09:10:27" 1141 | ], 1142 | "active-win-log [/mydev/code/npm/active-win-log] - .../commitMessageConfig.js [active-win-log]": [ 1143 | "2019-3-24 08:38:39", 1144 | "2019-3-24 08:38:44", 1145 | "2019-3-24 08:38:49", 1146 | "2019-3-24 08:38:54", 1147 | "2019-3-24 08:38:59" 1148 | ], 1149 | "": [ 1150 | "2019-3-24 08:42:36", 1151 | "2019-3-24 09:00:18" 1152 | ], 1153 | "active-win-log [/mydev/code/npm/active-win-log] - .../.npmignore [active-win-log]": [ 1154 | "2019-3-24 08:47:33", 1155 | "2019-3-24 08:47:38", 1156 | "2019-3-24 08:47:43", 1157 | "2019-3-24 08:47:48", 1158 | "2019-3-24 08:47:53", 1159 | "2019-3-24 08:50:44", 1160 | "2019-3-24 08:51:09", 1161 | "2019-3-24 08:51:15", 1162 | "2019-3-24 08:51:20", 1163 | "2019-3-24 08:51:25", 1164 | "2019-3-24 08:51:30", 1165 | "2019-3-24 08:51:35", 1166 | "2019-3-24 08:51:40", 1167 | "2019-3-24 08:52:15", 1168 | "2019-3-24 08:52:20", 1169 | "2019-3-24 08:52:25", 1170 | "2019-3-24 08:52:30", 1171 | "2019-3-24 08:52:35", 1172 | "2019-3-24 08:52:40", 1173 | "2019-3-24 08:52:45", 1174 | "2019-3-24 08:52:50", 1175 | "2019-3-24 08:52:55", 1176 | "2019-3-24 08:53:00", 1177 | "2019-3-24 08:53:05", 1178 | "2019-3-24 08:53:10", 1179 | "2019-3-24 08:53:15", 1180 | "2019-3-24 08:53:20", 1181 | "2019-3-24 08:53:25", 1182 | "2019-3-24 08:53:30", 1183 | "2019-3-24 08:53:35", 1184 | "2019-3-24 08:53:40", 1185 | "2019-3-24 08:53:45", 1186 | "2019-3-24 08:53:51", 1187 | "2019-3-24 08:54:11" 1188 | ], 1189 | "Delete": [ 1190 | "2019-3-24 08:55:01" 1191 | ], 1192 | "active-win-log [/mydev/code/npm/active-win-log] - .../bin/index.js [active-win-log]": [ 1193 | "2019-3-24 08:56:07", 1194 | "2019-3-24 08:56:12", 1195 | "2019-3-24 08:56:17", 1196 | "2019-3-24 08:56:22", 1197 | "2019-3-24 08:56:27", 1198 | "2019-3-24 08:56:32", 1199 | "2019-3-24 08:57:02", 1200 | "2019-3-24 08:57:07", 1201 | "2019-3-24 08:57:12", 1202 | "2019-3-24 08:57:17", 1203 | "2019-3-24 08:57:22", 1204 | "2019-3-24 08:57:37", 1205 | "2019-3-24 08:57:42", 1206 | "2019-3-24 08:57:57", 1207 | "2019-3-24 08:58:02", 1208 | "2019-3-24 08:58:07", 1209 | "2019-3-24 08:58:12", 1210 | "2019-3-24 08:59:33", 1211 | "2019-3-24 08:59:38", 1212 | "2019-3-24 08:59:43", 1213 | "2019-3-24 08:59:48", 1214 | "2019-3-24 08:59:53", 1215 | "2019-3-24 08:59:58", 1216 | "2019-3-24 09:00:03", 1217 | "2019-3-24 09:00:08", 1218 | "2019-3-24 09:00:13" 1219 | ] 1220 | }, 1221 | "Activity Monitor": { 1222 | "Activity Monitor (All Processes)": [ 1223 | "2019-3-24 08:35:15", 1224 | "2019-3-24 08:35:20", 1225 | "2019-3-24 08:35:48", 1226 | "2019-3-24 08:35:53", 1227 | "2019-3-24 08:41:10", 1228 | "2019-3-24 08:41:15", 1229 | "2019-3-24 08:41:20", 1230 | "2019-3-24 09:10:42", 1231 | "2019-3-24 09:11:32", 1232 | "2019-3-24 09:11:37", 1233 | "2019-3-24 09:11:47", 1234 | "2019-3-24 09:11:52", 1235 | "2019-3-24 09:11:57", 1236 | "2019-3-24 09:12:02", 1237 | "2019-3-24 09:12:17", 1238 | "2019-3-24 09:12:22", 1239 | "2019-3-24 09:12:27", 1240 | "2019-3-24 09:12:32", 1241 | "2019-3-24 09:12:37", 1242 | "2019-3-24 09:12:42", 1243 | "2019-3-24 09:12:47", 1244 | "2019-3-24 09:12:52", 1245 | "2019-3-24 09:12:57", 1246 | "2019-3-24 09:13:02", 1247 | "2019-3-24 09:13:07", 1248 | "2019-3-24 09:13:12", 1249 | "2019-3-24 09:14:08", 1250 | "2019-3-24 09:14:13", 1251 | "2019-3-24 09:14:23", 1252 | "2019-3-24 09:14:28", 1253 | "2019-3-24 09:14:33", 1254 | "2019-3-24 09:14:38", 1255 | "2019-3-24 09:14:43", 1256 | "2019-3-24 09:14:48" 1257 | ], 1258 | "": [ 1259 | "2019-3-24 09:10:37", 1260 | "2019-3-24 09:14:18" 1261 | ], 1262 | "node (71241)": [ 1263 | "2019-3-24 09:14:53", 1264 | "2019-3-24 09:14:58", 1265 | "2019-3-24 09:15:03", 1266 | "2019-3-24 09:15:08", 1267 | "2019-3-24 09:15:13", 1268 | "2019-3-24 09:15:18", 1269 | "2019-3-24 09:15:23", 1270 | "2019-3-24 09:15:28", 1271 | "2019-3-24 09:15:33", 1272 | "2019-3-24 09:15:38", 1273 | "2019-3-24 09:15:43", 1274 | "2019-3-24 09:15:48", 1275 | "2019-3-24 09:15:53", 1276 | "2019-3-24 09:15:58", 1277 | "2019-3-24 09:16:03" 1278 | ] 1279 | }, 1280 | "loginwindow": { 1281 | "": [ 1282 | "2019-3-24 08:37:08", 1283 | "2019-3-24 09:03:09", 1284 | "2019-3-24 09:03:15", 1285 | "2019-3-24 09:03:20", 1286 | "2019-3-24 09:03:25", 1287 | "2019-3-24 09:03:30", 1288 | "2019-3-24 09:03:35", 1289 | "2019-3-24 09:03:40", 1290 | "2019-3-24 09:03:45", 1291 | "2019-3-24 09:03:50", 1292 | "2019-3-24 09:03:55", 1293 | "2019-3-24 09:04:00", 1294 | "2019-3-24 09:04:05", 1295 | "2019-3-24 09:04:10", 1296 | "2019-3-24 09:04:15", 1297 | "2019-3-24 09:04:20", 1298 | "2019-3-24 09:04:25", 1299 | "2019-3-24 09:04:30", 1300 | "2019-3-24 09:04:35", 1301 | "2019-3-24 09:04:40", 1302 | "2019-3-24 09:04:45", 1303 | "2019-3-24 09:04:50", 1304 | "2019-3-24 09:04:55", 1305 | "2019-3-24 09:05:00", 1306 | "2019-3-24 09:05:05", 1307 | "2019-3-24 09:05:10", 1308 | "2019-3-24 09:05:15", 1309 | "2019-3-24 09:05:20", 1310 | "2019-3-24 09:05:25", 1311 | "2019-3-24 09:05:30", 1312 | "2019-3-24 09:05:35", 1313 | "2019-3-24 09:05:40", 1314 | "2019-3-24 09:05:46", 1315 | "2019-3-24 09:05:51", 1316 | "2019-3-24 09:05:56", 1317 | "2019-3-24 09:06:01", 1318 | "2019-3-24 09:06:06", 1319 | "2019-3-24 09:06:11", 1320 | "2019-3-24 09:06:16", 1321 | "2019-3-24 09:06:21", 1322 | "2019-3-24 09:06:26", 1323 | "2019-3-24 09:06:31", 1324 | "2019-3-24 09:06:36", 1325 | "2019-3-24 09:06:41", 1326 | "2019-3-24 09:06:46", 1327 | "2019-3-24 09:06:51", 1328 | "2019-3-24 09:06:56", 1329 | "2019-3-24 09:07:01", 1330 | "2019-3-24 09:07:06", 1331 | "2019-3-24 09:07:11", 1332 | "2019-3-24 09:07:16", 1333 | "2019-3-24 09:07:21", 1334 | "2019-3-24 09:07:26", 1335 | "2019-3-24 09:07:31", 1336 | "2019-3-24 09:07:36", 1337 | "2019-3-24 09:07:41", 1338 | "2019-3-24 09:07:46", 1339 | "2019-3-24 09:07:51", 1340 | "2019-3-24 09:07:56", 1341 | "2019-3-24 09:08:01", 1342 | "2019-3-24 09:08:06", 1343 | "2019-3-24 09:08:11", 1344 | "2019-3-24 09:08:17", 1345 | "2019-3-24 09:08:22", 1346 | "2019-3-24 09:08:27", 1347 | "2019-3-24 09:08:32", 1348 | "2019-3-24 09:08:37", 1349 | "2019-3-24 09:08:42", 1350 | "2019-3-24 09:08:47", 1351 | "2019-3-24 09:08:52", 1352 | "2019-3-24 09:08:57", 1353 | "2019-3-24 09:09:02", 1354 | "2019-3-24 09:09:07", 1355 | "2019-3-24 09:09:12", 1356 | "2019-3-24 09:09:17", 1357 | "2019-3-24 09:09:22", 1358 | "2019-3-24 09:09:27", 1359 | "2019-3-24 09:09:32", 1360 | "2019-3-24 09:09:37", 1361 | "2019-3-24 09:09:42" 1362 | ] 1363 | }, 1364 | "Messages": { 1365 | "": [ 1366 | "2019-3-24 08:48:54", 1367 | "2019-3-24 08:48:59", 1368 | "2019-3-24 08:49:49", 1369 | "2019-3-24 08:49:54", 1370 | "2019-3-24 08:49:59", 1371 | "2019-3-24 08:50:04", 1372 | "2019-3-24 08:50:09", 1373 | "2019-3-24 08:50:14", 1374 | "2019-3-24 08:50:19", 1375 | "2019-3-24 08:50:24", 1376 | "2019-3-24 08:50:29", 1377 | "2019-3-24 09:00:54", 1378 | "2019-3-24 09:00:59", 1379 | "2019-3-24 09:01:04", 1380 | "2019-3-24 09:01:09", 1381 | "2019-3-24 09:01:14", 1382 | "2019-3-24 09:01:19", 1383 | "2019-3-24 09:01:24", 1384 | "2019-3-24 09:01:29", 1385 | "2019-3-24 09:01:34", 1386 | "2019-3-24 09:01:39", 1387 | "2019-3-24 09:01:44", 1388 | "2019-3-24 09:01:49", 1389 | "2019-3-24 09:01:54", 1390 | "2019-3-24 09:01:59", 1391 | "2019-3-24 09:02:04", 1392 | "2019-3-24 09:02:09", 1393 | "2019-3-24 09:02:14", 1394 | "2019-3-24 09:02:19", 1395 | "2019-3-24 09:02:24", 1396 | "2019-3-24 09:02:29", 1397 | "2019-3-24 09:02:34", 1398 | "2019-3-24 09:02:39", 1399 | "2019-3-24 09:02:44", 1400 | "2019-3-24 09:02:49", 1401 | "2019-3-24 09:02:54", 1402 | "2019-3-24 09:02:59", 1403 | "2019-3-24 09:03:04", 1404 | "2019-3-24 09:09:47", 1405 | "2019-3-24 09:09:52", 1406 | "2019-3-24 09:16:14", 1407 | "2019-3-24 09:16:19" 1408 | ] 1409 | }, 1410 | "Finder": { 1411 | ".active-win-log": [ 1412 | "2019-3-24 08:51:45" 1413 | ], 1414 | "active-win-log": [ 1415 | "2019-3-24 08:51:50", 1416 | "2019-3-24 09:12:07" 1417 | ] 1418 | } 1419 | } 1420 | } 1421 | } 1422 | --------------------------------------------------------------------------------