diff --git a/.drone.yml b/.drone.yml
index 4a88427eee..662529bf2e 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -50,7 +50,8 @@ pipeline:
     pull: true
     commands:
       - npm install
-      - make stylesheets-check
+      - make css
+      - make js
     when:
       event: [ push, tag, pull_request ]
 
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000000..41cad889b1
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,25 @@
+root: true
+
+extends:
+  - eslint:recommended
+
+parserOptions:
+  ecmaVersion: 2015
+
+env:
+  browser: true
+  jquery: true
+  es6: true
+
+globals:
+  Clipboard: false
+  CodeMirror: false
+  emojify: false
+  SimpleMDE: false
+  Vue: false
+  Dropzone: false
+  u2fApi: false
+  hljs: false
+
+rules:
+  no-unused-vars: [error, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}]
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 260727f15e..fd3b35030f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,9 +65,9 @@ high-level discussions.
 ## Testing redux
 
 Before submitting a pull request, run all the tests for the whole tree
-to make sure your changes don't cause regression elsewhere.  
+to make sure your changes don't cause regression elsewhere.
 
-Here's how to run the test suite: 
+Here's how to run the test suite:
 
 - Install the correct version of the drone-cli package.  As of this
   writing, the correct drone-cli version is
@@ -75,7 +75,7 @@ Here's how to run the test suite:
 - Ensure you have enough free disk space.  You will need at least
   15-20 Gb of free disk space to hold all of the containers drone
   creates (a default AWS or GCE disk size won't work -- see
-  [#6243](https://github.com/go-gitea/gitea/issues/6243)).  
+  [#6243](https://github.com/go-gitea/gitea/issues/6243)).
 - Change into the base directory of your copy of the gitea repository,
   and run `drone exec --local --build-event pull_request`.
 
@@ -114,7 +114,7 @@ Generally, the go build tools are installed as-needed in the `Makefile`.
 An exception are the tools to build the CSS and images.
 
 - To build CSS: Install [Node.js](https://nodejs.org/en/download/package-manager) at version 8.0 or above
-  with `npm` and then run `npm install` and `make generate-stylesheets`.
+  with `npm` and then run `npm install` and `make css`.
 - To build Images: ImageMagick, inkscape and zopflipng binaries must be
   available in your `PATH` to run `make generate-images`.
 
@@ -214,7 +214,7 @@ to the maintainers team. If a maintainer is inactive for more than 3
 months and forgets to leave the maintainers team, the owners may move
 him or her from the maintainers team to the advisors team.
 For security reasons, Maintainers should use 2FA for their accounts and
-if possible provide gpg signed commits. 
+if possible provide gpg signed commits.
 https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
 https://help.github.com/articles/signing-commits-with-gpg/
 
@@ -281,7 +281,7 @@ be reviewed by two maintainers and must pass the automatic tests.
   * Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
   * When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
 * If it is bugfix version create PR for changelog on branch `release/v$vmaj.$vmin` and wait till it is reviewed and merged.
-* Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`. 
+* Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
 * And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically created a release and upload all the compiled binary. (But currently it didn't add the release notes automatically. Maybe we should fix that.)
 * If needed send PR for changelog on branch `master`.
 * Send PR to [blog repository](https://github.com/go-gitea/blog) announcing the release.
diff --git a/Makefile b/Makefile
index 2b77ce5dca..718836be65 100644
--- a/Makefile
+++ b/Makefile
@@ -365,33 +365,55 @@ release-compress:
 	fi
 	cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
 
-.PHONY: javascripts
-javascripts: public/js/index.js
-
-.IGNORE: public/js/index.js
-public/js/index.js: $(JAVASCRIPTS)
-	cat $< >| $@
-
-.PHONY: stylesheets-check
-stylesheets-check: generate-stylesheets
-	@diff=$$(git diff public/css/*); \
-	if [ -n "$$diff" ]; then \
-		echo "Please run 'make generate-stylesheets' and commit the result:"; \
-		echo "$${diff}"; \
+.PHONY: js
+js:
+	@if ([ ! -d "$(PWD)/node_modules" ]); then \
+		echo "node_modules directory is absent, please run 'npm install' first"; \
 		exit 1; \
 	fi;
+	@hash npx > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
+		echo "Please install npm version 5.2+"; \
+		exit 1; \
+	fi;
+	npx eslint public/js
 
-.PHONY: generate-stylesheets
-generate-stylesheets:
+.PHONY: css
+css:
+	@if ([ ! -d "$(PWD)/node_modules" ]); then \
+		echo "node_modules directory is absent, please run 'npm install' first"; \
+		exit 1; \
+	fi;
 	@hash npx > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
 		echo "Please install npm version 5.2+"; \
 		exit 1; \
 	fi;
-	$(eval BROWSERS := "> 1%, last 2 firefox versions, last 2 safari versions, ie 11")
-	npx lesshint  public/less/
+
+	npx lesshint public/less/
 	npx lessc --clean-css="--s0 -b" public/less/index.less public/css/index.css
 	$(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),npx lessc --clean-css="--s0 -b" public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;)
-	$(foreach file, $(wildcard public/css/*),npx postcss --use autoprefixer --autoprefixer.browsers $(BROWSERS) -o $(file) $(file);)
+	npx postcss --use autoprefixer --no-map --replace public/css/*
+
+	@diff=$$(git diff public/css/*); \
+	if ([ ! -z "$CI" ] && [ -n "$$diff" ]); then \
+		echo "Generated files in public/css have changed, please commit the result:"; \
+		echo "$${diff}"; \
+		exit 1; \
+	fi;
+
+.PHONY: javascripts
+javascripts:
+	echo "'make javascripts' is deprecated, please use 'make js'"
+	$(MAKE) js
+
+.PHONY: stylesheets-check
+stylesheets-check:
+	echo "'make stylesheets-check' is deprecated, please use 'make css'"
+	$(MAKE) css
+
+.PHONY: generate-stylesheets
+generate-stylesheets:
+	echo "'make generate-stylesheets' is deprecated, please use 'make css'"
+	$(MAKE) css
 
 .PHONY: swagger-ui
 swagger-ui:
diff --git a/docs/content/doc/advanced/hacking-on-gitea.en-us.md b/docs/content/doc/advanced/hacking-on-gitea.en-us.md
index 1fabc1a118..48a4510545 100644
--- a/docs/content/doc/advanced/hacking-on-gitea.en-us.md
+++ b/docs/content/doc/advanced/hacking-on-gitea.en-us.md
@@ -136,30 +136,36 @@ You should lint, vet and spell-check with:
 make vet lint misspell-check
 ```
 
-### Updating the stylesheets
+### Updating CSS
 
-To generate the stylsheets, you will need [Node.js](https://nodejs.org/) at version 8.0 or above.
+To generate the CSS, you will need [Node.js](https://nodejs.org/) 8.0 or greater and the build dependencies:
 
-At present we use [less](http://lesscss.org/) and [postcss](https://postcss.org) to generate our stylesheets. Do
-**not** edit the files in `public/css/` directly, as they are generated from
-`lessc` from the files in `public/less/`.
+```bash
+npm install
+```
 
-If you wish to work on the stylesheets, you will need to install `lessc` the
-less compiler and `postcss`. The recommended way to do this is using `npm install`:
+At present we use [less](http://lesscss.org/) and [postcss](https://postcss.org) to generate our CSS. Do
+**not** edit the files in `public/css` directly, as they are generated from `lessc` from the files in `public/less`.
+
+Edit files in `public/less`, run the linter, regenerate the CSS and commit all changed files:
 
 ```bash
-cd "$GOPATH/src/code.gitea.io/gitea"
-npm install
+make css
 ```
 
-You can then edit the less stylesheets and regenerate the stylesheets using:
+### Updating JS
+
+To run the JavaScript linter you will need [Node.js](https://nodejs.org/) 8.0 or greater and the build dependencies:
 
 ```bash
-make generate-stylesheets
+npm install
 ```
 
-You should commit both the changes to the css and the less files when making
-PRs.
+Edit files in `public/js` and run the linter:
+
+```bash
+make js
+```
 
 ### Updating the API
 
diff --git a/package-lock.json b/package-lock.json
index 57a39821e9..6a81145ec1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2,6 +2,26 @@
   "requires": true,
   "lockfileVersion": 1,
   "dependencies": {
+    "@babel/code-frame": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
+      "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+      "dev": true,
+      "requires": {
+        "@babel/highlight": "^7.0.0"
+      }
+    },
+    "@babel/highlight": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
+      "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.0.0",
+        "esutils": "^2.0.2",
+        "js-tokens": "^4.0.0"
+      }
+    },
     "@mrmlnc/readdir-enhanced": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
@@ -18,12 +38,23 @@
       "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
       "dev": true
     },
+    "acorn": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
+      "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
+      "dev": true
+    },
+    "acorn-jsx": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz",
+      "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==",
+      "dev": true
+    },
     "ajv": {
       "version": "6.9.1",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz",
       "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==",
       "dev": true,
-      "optional": true,
       "requires": {
         "fast-deep-equal": "^2.0.1",
         "fast-json-stable-stringify": "^2.0.0",
@@ -35,22 +66,19 @@
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
           "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "json-schema-traverse": {
           "version": "0.4.1",
           "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
           "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "uri-js": {
           "version": "4.2.2",
           "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
           "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
           "dev": true,
-          "optional": true,
           "requires": {
             "punycode": "^2.1.0"
           }
@@ -63,6 +91,18 @@
       "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
       "dev": true
     },
+    "ansi-escapes": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+      "dev": true
+    },
+    "ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+      "dev": true
+    },
     "ansi-styles": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
@@ -159,6 +199,12 @@
       "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
       "dev": true
     },
+    "astral-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+      "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+      "dev": true
+    },
     "asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -385,6 +431,12 @@
         }
       }
     },
+    "chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+      "dev": true
+    },
     "class-utils": {
       "version": "0.3.6",
       "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
@@ -408,6 +460,21 @@
         }
       }
     },
+    "cli-cursor": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "dev": true,
+      "requires": {
+        "restore-cursor": "^2.0.0"
+      }
+    },
+    "cli-width": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+      "dev": true
+    },
     "collection-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -473,6 +540,19 @@
         "parse-json": "^4.0.0"
       }
     },
+    "cross-spawn": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "dev": true,
+      "requires": {
+        "nice-try": "^1.0.4",
+        "path-key": "^2.0.1",
+        "semver": "^5.5.0",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      }
+    },
     "cssesc": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz",
@@ -500,6 +580,12 @@
       "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
       "dev": true
     },
+    "deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
     "define-property": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
@@ -551,12 +637,27 @@
         "path-type": "^3.0.0"
       }
     },
+    "doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2"
+      }
+    },
     "electron-to-chromium": {
       "version": "1.3.133",
       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.133.tgz",
       "integrity": "sha512-lyoC8aoqbbDqsprb6aPdt9n3DpOZZzdz/T4IZKsR0/dkZIxnJVUjjcpOSwA66jPRIOyDAamCTAUqweU05kKNSg==",
       "dev": true
     },
+    "emoji-regex": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+      "dev": true
+    },
     "error-ex": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -572,12 +673,158 @@
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
       "dev": true
     },
+    "eslint": {
+      "version": "5.16.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz",
+      "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "ajv": "^6.9.1",
+        "chalk": "^2.1.0",
+        "cross-spawn": "^6.0.5",
+        "debug": "^4.0.1",
+        "doctrine": "^3.0.0",
+        "eslint-scope": "^4.0.3",
+        "eslint-utils": "^1.3.1",
+        "eslint-visitor-keys": "^1.0.0",
+        "espree": "^5.0.1",
+        "esquery": "^1.0.1",
+        "esutils": "^2.0.2",
+        "file-entry-cache": "^5.0.1",
+        "functional-red-black-tree": "^1.0.1",
+        "glob": "^7.1.2",
+        "globals": "^11.7.0",
+        "ignore": "^4.0.6",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "inquirer": "^6.2.2",
+        "js-yaml": "^3.13.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.3.0",
+        "lodash": "^4.17.11",
+        "minimatch": "^3.0.4",
+        "mkdirp": "^0.5.1",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.8.2",
+        "path-is-inside": "^1.0.2",
+        "progress": "^2.0.0",
+        "regexpp": "^2.0.1",
+        "semver": "^5.5.1",
+        "strip-ansi": "^4.0.0",
+        "strip-json-comments": "^2.0.1",
+        "table": "^5.2.3",
+        "text-table": "^0.2.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "ignore": {
+          "version": "4.0.6",
+          "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+          "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+          "dev": true
+        },
+        "import-fresh": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz",
+          "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==",
+          "dev": true,
+          "requires": {
+            "parent-module": "^1.0.0",
+            "resolve-from": "^4.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+          "dev": true
+        },
+        "resolve-from": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+          "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-scope": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
+      "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
+      "dev": true,
+      "requires": {
+        "esrecurse": "^4.1.0",
+        "estraverse": "^4.1.1"
+      }
+    },
+    "eslint-utils": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
+      "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
+      "dev": true
+    },
+    "eslint-visitor-keys": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
+      "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==",
+      "dev": true
+    },
+    "espree": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz",
+      "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==",
+      "dev": true,
+      "requires": {
+        "acorn": "^6.0.7",
+        "acorn-jsx": "^5.0.0",
+        "eslint-visitor-keys": "^1.0.0"
+      }
+    },
     "esprima": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
       "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
       "dev": true
     },
+    "esquery": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+      "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^4.0.0"
+      }
+    },
+    "esrecurse": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^4.1.0"
+      }
+    },
+    "estraverse": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+      "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+      "dev": true
+    },
+    "esutils": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+      "dev": true
+    },
     "expand-brackets": {
       "version": "2.1.4",
       "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@@ -634,6 +881,17 @@
         }
       }
     },
+    "external-editor": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
+      "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
+      "dev": true,
+      "requires": {
+        "chardet": "^0.7.0",
+        "iconv-lite": "^0.4.24",
+        "tmp": "^0.0.33"
+      }
+    },
     "extglob": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
@@ -703,8 +961,7 @@
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
       "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "fast-glob": {
       "version": "2.2.6",
@@ -720,6 +977,30 @@
         "micromatch": "^3.1.10"
       }
     },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
+    },
+    "figures": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "^1.0.5"
+      }
+    },
+    "file-entry-cache": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+      "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+      "dev": true,
+      "requires": {
+        "flat-cache": "^2.0.1"
+      }
+    },
     "fill-range": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@@ -743,6 +1024,23 @@
         }
       }
     },
+    "flat-cache": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+      "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+      "dev": true,
+      "requires": {
+        "flatted": "^2.0.0",
+        "rimraf": "2.6.3",
+        "write": "1.0.3"
+      }
+    },
+    "flatted": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz",
+      "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==",
+      "dev": true
+    },
     "flatten": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
@@ -808,6 +1106,12 @@
       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
       "dev": true
     },
+    "functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+      "dev": true
+    },
     "get-value": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
@@ -855,6 +1159,12 @@
       "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=",
       "dev": true
     },
+    "globals": {
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+      "dev": true
+    },
     "globby": {
       "version": "8.0.2",
       "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz",
@@ -933,6 +1243,15 @@
         }
       }
     },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
     "ignore": {
       "version": "3.3.10",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
@@ -956,6 +1275,12 @@
         "resolve-from": "^3.0.0"
       }
     },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
+    },
     "indexes-of": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
@@ -978,6 +1303,44 @@
       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
       "dev": true
     },
+    "inquirer": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz",
+      "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==",
+      "dev": true,
+      "requires": {
+        "ansi-escapes": "^3.2.0",
+        "chalk": "^2.4.2",
+        "cli-cursor": "^2.1.0",
+        "cli-width": "^2.0.0",
+        "external-editor": "^3.0.3",
+        "figures": "^2.0.0",
+        "lodash": "^4.17.11",
+        "mute-stream": "0.0.7",
+        "run-async": "^2.2.0",
+        "rxjs": "^6.4.0",
+        "string-width": "^2.1.0",
+        "strip-ansi": "^5.1.0",
+        "through": "^2.3.6"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
+      }
+    },
     "is-accessor-descriptor": {
       "version": "0.1.6",
       "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
@@ -1067,6 +1430,12 @@
       "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
       "dev": true
     },
+    "is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true
+    },
     "is-glob": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
@@ -1105,6 +1474,12 @@
         "isobject": "^3.0.1"
       }
     },
+    "is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+      "dev": true
+    },
     "is-windows": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -1117,12 +1492,24 @@
       "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
       "dev": true
     },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
     "isobject": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
       "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
       "dev": true
     },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
     "js-yaml": {
       "version": "3.13.1",
       "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
@@ -1139,6 +1526,12 @@
       "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
       "dev": true
     },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "dev": true
+    },
     "kind-of": {
       "version": "6.0.2",
       "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
@@ -1545,6 +1938,16 @@
         "strip-json-comments": "^2.0.0"
       }
     },
+    "levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      }
+    },
     "lodash": {
       "version": "4.17.11",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
@@ -1605,6 +2008,12 @@
         "to-regex": "^3.0.2"
       }
     },
+    "mimic-fn": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+      "dev": true
+    },
     "minimatch": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -1614,6 +2023,12 @@
         "brace-expansion": "^1.1.7"
       }
     },
+    "minimist": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+      "dev": true
+    },
     "mixin-deep": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
@@ -1635,12 +2050,27 @@
         }
       }
     },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "dev": true,
+      "requires": {
+        "minimist": "0.0.8"
+      }
+    },
     "ms": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
       "dev": true
     },
+    "mute-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+      "dev": true
+    },
     "nanomatch": {
       "version": "1.2.13",
       "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -1660,6 +2090,18 @@
         "to-regex": "^3.0.1"
       }
     },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
+    },
+    "nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
+    },
     "node-releases": {
       "version": "1.1.19",
       "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.19.tgz",
@@ -1746,6 +2188,52 @@
         "wrappy": "1"
       }
     },
+    "onetime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "dev": true,
+      "requires": {
+        "mimic-fn": "^1.0.0"
+      }
+    },
+    "optionator": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "dev": true,
+      "requires": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.4",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "wordwrap": "~1.0.0"
+      }
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true
+    },
+    "parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "requires": {
+        "callsites": "^3.0.0"
+      },
+      "dependencies": {
+        "callsites": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+          "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+          "dev": true
+        }
+      }
+    },
     "parse-json": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
@@ -1774,6 +2262,18 @@
       "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
       "dev": true
     },
+    "path-is-inside": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "dev": true
+    },
+    "path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "dev": true
+    },
     "path-type": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
@@ -1900,12 +2400,23 @@
         "uniq": "^1.0.1"
       }
     },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true
+    },
+    "progress": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+      "dev": true
+    },
     "punycode": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "regex-not": {
       "version": "1.0.2",
@@ -1917,6 +2428,12 @@
         "safe-regex": "^1.1.0"
       }
     },
+    "regexpp": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+      "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
+      "dev": true
+    },
     "repeat-element": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
@@ -1941,12 +2458,49 @@
       "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
       "dev": true
     },
+    "restore-cursor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "dev": true,
+      "requires": {
+        "onetime": "^2.0.0",
+        "signal-exit": "^3.0.2"
+      }
+    },
     "ret": {
       "version": "0.1.15",
       "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
       "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
       "dev": true
     },
+    "rimraf": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+      "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.3"
+      }
+    },
+    "run-async": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+      "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+      "dev": true,
+      "requires": {
+        "is-promise": "^2.1.0"
+      }
+    },
+    "rxjs": {
+      "version": "6.5.2",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz",
+      "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==",
+      "dev": true,
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -1967,8 +2521,7 @@
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "semver": {
       "version": "5.7.0",
@@ -1999,12 +2552,44 @@
         }
       }
     },
+    "shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "dev": true,
+      "requires": {
+        "shebang-regex": "^1.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "dev": true
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "dev": true
+    },
     "slash": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
       "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
       "dev": true
     },
+    "slice-ansi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+      "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.0",
+        "astral-regex": "^1.0.0",
+        "is-fullwidth-code-point": "^2.0.0"
+      }
+    },
     "snapdragon": {
       "version": "0.8.2",
       "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -2173,6 +2758,25 @@
         }
       }
     },
+    "string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
+      "requires": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^3.0.0"
+      }
+    },
     "strip-json-comments": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -2188,6 +2792,67 @@
         "has-flag": "^3.0.0"
       }
     },
+    "table": {
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/table/-/table-5.3.3.tgz",
+      "integrity": "sha512-3wUNCgdWX6PNpOe3amTTPWPuF6VGvgzjKCaO1snFj0z7Y3mUPWf5+zDtxUVGispJkDECPmR29wbzh6bVMOHbcw==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.9.1",
+        "lodash": "^4.17.11",
+        "slice-ansi": "^2.1.0",
+        "string-width": "^3.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true
+    },
+    "tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "dev": true,
+      "requires": {
+        "os-tmpdir": "~1.0.2"
+      }
+    },
     "to-object-path": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
@@ -2257,6 +2922,12 @@
         }
       }
     },
+    "tslib": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
+      "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
+      "dev": true
+    },
     "tunnel-agent": {
       "version": "0.6.0",
       "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@@ -2267,6 +2938,15 @@
         "safe-buffer": "^5.0.1"
       }
     },
+    "type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "~1.1.2"
+      }
+    },
     "union-value": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
@@ -2360,11 +3040,35 @@
       "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
       "dev": true
     },
+    "which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+      "dev": true
+    },
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
       "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
       "dev": true
+    },
+    "write": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+      "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+      "dev": true,
+      "requires": {
+        "mkdirp": "^0.5.1"
+      }
     }
   }
 }
diff --git a/package.json b/package.json
index 094941980f..1bbe6cf8ae 100644
--- a/package.json
+++ b/package.json
@@ -2,9 +2,16 @@
   "license": "MIT",
   "devDependencies": {
     "autoprefixer": "9.5.1",
+    "eslint": "5.16.0",
     "less": "3.9.0",
     "less-plugin-clean-css": "1.5.1",
     "lesshint": "^6.3.6",
-    "postcss-cli-simple": "3.0.0"
-  }
+    "postcss-cli": "6.1.2"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 firefox versions",
+    "last 2 safari versions",
+    "ie 11"
+  ]
 }
diff --git a/public/js/draw.js b/public/js/draw.js
index fd99e1a73d..518d1ec545 100644
--- a/public/js/draw.js
+++ b/public/js/draw.js
@@ -1,13 +1,15 @@
+/* globals gitGraph */
+
 $(document).ready(function () {
 	var graphList = [];
-	
+
 	if (!document.getElementById('graph-canvas')) {
 		return;
 	}
-	
+
 	$("#graph-raw-list li span.node-relation").each(function () {
 		graphList.push($(this).text());
 	})
-	
+
 	gitGraph(document.getElementById('graph-canvas'), graphList);
 })
diff --git a/public/js/index.js b/public/js/index.js
index 79d0569f9b..96d55eca87 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -1,3 +1,6 @@
+/* globals wipPrefixes, issuesTribute, emojiTribute */
+/* exported timeAddManual, toggleStopwatch, cancelStopwatch, initHeatmap */
+/* exported toggleDeadlineForm, setDeadline, deleteDependencyModal, cancelCodeComment, onOAuthLoginClick */
 'use strict';
 
 function htmlEncode(text) {
@@ -89,7 +92,7 @@ if (!Array.from) {
 if (typeof Object.assign != 'function') {
     // Must be writable: true, enumerable: false, configurable: true
     Object.defineProperty(Object, "assign", {
-        value: function assign(target, varArgs) { // .length of function is 2
+        value: function assign(target, _varArgs) { // .length of function is 2
             'use strict';
             if (target == null) { // TypeError if undefined or null
                 throw new TypeError('Cannot convert undefined or null to object');
@@ -131,8 +134,8 @@ function initCommentPreviewTab($form) {
                 var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]');
                 $previewPanel.html(data);
                 emojify.run($previewPanel[0]);
-                $('pre code', $previewPanel[0]).each(function (i, block) {
-                    hljs.highlightBlock(block);
+                $('pre code', $previewPanel[0]).each(function () {
+                    hljs.highlightBlock(this);
                 });
             }
         );
@@ -161,8 +164,8 @@ function initEditPreviewTab($form) {
                     var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]');
                     $previewPanel.html(data);
                     emojify.run($previewPanel[0]);
-                    $('pre code', $previewPanel[0]).each(function (i, block) {
-                        hljs.highlightBlock(block);
+                    $('pre code', $previewPanel[0]).each(function () {
+                        hljs.highlightBlock(this);
                     });
                 }
             );
@@ -355,7 +358,8 @@ function reload() {
 }
 
 function initImagePaste(target) {
-    target.each(function(i, field) {
+    target.each(function() {
+        var field = this;
         field.addEventListener('paste', function(event){
             retrieveImageFromClipboardAsBlob(event, function(img) {
                 var name = img.name.substr(0, img.name.lastIndexOf('.'));
@@ -606,7 +610,7 @@ function initInstall() {
         $('#sql_settings').show();
 
         $('#pgsql_settings').toggle(dbType === "PostgreSQL");
-        $.each(dbDefaults, function(type, defaultHost) {
+        $.each(dbDefaults, function(_type, defaultHost) {
             if ($('#db_host').val() == defaultHost) {
                 $('#db_host').val(dbDefaults[dbType]);
                 return false;
@@ -636,8 +640,7 @@ function initInstall() {
     });
     $('#enable-openid-signin input').change(function () {
         if ($(this).is(':checked')) {
-            if ( $('#disable-registration input').is(':checked') ) {
-            } else {
+            if (!$('#disable-registration input').is(':checked')) {
                 $('#enable-openid-signup').checkbox('check');
             }
         } else {
@@ -669,7 +672,7 @@ function initRepository() {
         $dropdown.dropdown({
             fullTextSearch: true,
             selectOnKeydown: false,
-            onChange: function (text, value, $choice) {
+            onChange: function (_text, _value, $choice) {
                 if ($choice.data('url')) {
                     window.location.href = $choice.data('url');
                 }
@@ -756,9 +759,6 @@ function initRepository() {
     }
 
     // Milestones
-    if ($('.repository.milestones').length > 0) {
-
-    }
     if ($('.repository.new.milestone').length > 0) {
         var $datepicker = $('.milestone.datepicker');
         $datepicker.datetimepicker({
@@ -857,8 +857,8 @@ function initRepository() {
                             } else {
                                 $renderContent.html(data.content);
                                 emojify.run($renderContent[0]);
-                                $('pre code', $renderContent[0]).each(function (i, block) {
-                                    hljs.highlightBlock(block);
+                                $('pre code', $renderContent[0]).each(function () {
+                                    hljs.highlightBlock(this);
                                 });
                             }
                         });
@@ -912,7 +912,7 @@ function initRepository() {
             $(this).parent().hide();
         });
         $('.merge-button > .dropdown').dropdown({
-            onChange: function (text, value, $choice) {
+            onChange: function (_text, _value, $choice) {
                 if ($choice.data('do')) {
                     $mergeButton.find('.button-text').text($choice.text());
                     $mergeButton.data('do', $choice.data('do'));
@@ -930,16 +930,13 @@ function initRepository() {
 
     // Diff
     if ($('.repository.diff').length > 0) {
-        var $counter = $('.diff-counter');
-        if ($counter.length >= 1) {
-            $counter.each(function (i, item) {
-                var $item = $(item);
-                var addLine = $item.find('span[data-line].add').data("line");
-                var delLine = $item.find('span[data-line].del').data("line");
-                var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100;
-                $item.find(".bar .add").css("width", addPercent + "%");
-            });
-        }
+        $('.diff-counter').each(function () {
+            var $item = $(this);
+            var addLine = $item.find('span[data-line].add').data("line");
+            var delLine = $item.find('span[data-line].del').data("line");
+            var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100;
+            $item.find(".bar .add").css("width", addPercent + "%");
+        });
     }
 
     // Quick start and repository home
@@ -982,7 +979,7 @@ function initRepository() {
 var toggleMigrations = function(){
     var authUserName = $('#auth_username').val();
     var cloneAddr = $('#clone_addr').val();
-    if (!$('#mirror').is(":checked") && (authUserName!=undefined && authUserName.length > 0) 
+    if (!$('#mirror').is(":checked") && (authUserName!=undefined && authUserName.length > 0)
     && (cloneAddr!=undefined && (cloneAddr.startsWith("https://github.com") || cloneAddr.startsWith("http://github.com")))) {
         $('#migrate_items').show();
     } else {
@@ -1085,8 +1082,9 @@ function assingMenuAttributes(menu) {
     var id = Math.floor(Math.random() * Math.floor(1000000));
     menu.attr('data-write', menu.attr('data-write') + id);
     menu.attr('data-preview', menu.attr('data-preview') + id);
-    menu.find('.item').each(function(i, item) {
-        $(item).attr('data-tab', $(item).attr('data-tab') + id);
+    menu.find('.item').each(function() {
+        var tab = $(this).attr('data-tab') + id;
+        $(this).attr('data-tab', tab);
     });
     menu.parent().find("*[data-tab='write']").attr('data-tab', 'write' + id);
     menu.parent().find("*[data-tab='preview']").attr('data-tab', 'preview' + id);
@@ -1170,22 +1168,20 @@ String.prototype.endsWith = function (pattern) {
 };
 
 // Adding function to get the cursor position in a text field to jQuery object.
-(function ($, undefined) {
-    $.fn.getCursorPosition = function () {
-        var el = $(this).get(0);
-        var pos = 0;
-        if ('selectionStart' in el) {
-            pos = el.selectionStart;
-        } else if ('selection' in document) {
-            el.focus();
-            var Sel = document.selection.createRange();
-            var SelLength = document.selection.createRange().text.length;
-            Sel.moveStart('character', -el.value.length);
-            pos = Sel.text.length - SelLength;
-        }
-        return pos;
+$.fn.getCursorPosition = function () {
+    var el = $(this).get(0);
+    var pos = 0;
+    if ('selectionStart' in el) {
+        pos = el.selectionStart;
+    } else if ('selection' in document) {
+        el.focus();
+        var Sel = document.selection.createRange();
+        var SelLength = document.selection.createRange().text.length;
+        Sel.moveStart('character', -el.value.length);
+        pos = Sel.text.length - SelLength;
     }
-})(jQuery);
+    return pos;
+}
 
 function setSimpleMDE($editArea) {
     if (codeMirrorEditor) {
@@ -1249,7 +1245,7 @@ function setCodeMirror($editArea) {
     codeMirrorEditor = CodeMirror.fromTextArea($editArea[0], {
         lineNumbers: true
     });
-    codeMirrorEditor.on("change", function (cm, change) {
+    codeMirrorEditor.on("change", function (cm, _change) {
         $editArea.val(cm.getValue());
     });
 
@@ -1271,10 +1267,13 @@ function initEditor() {
     $editFilename.keyup(function (e) {
         var $section = $('.breadcrumb span.section');
         var $divider = $('.breadcrumb div.divider');
+        var value;
+        var parts;
+
         if (e.keyCode == 8) {
             if ($(this).getCursorPosition() == 0) {
                 if ($section.length > 0) {
-                    var value = $section.last().find('a').text();
+                    value = $section.last().find('a').text();
                     $(this).val(value + $(this).val());
                     $(this)[0].setSelectionRange(value.length, value.length);
                     $section.last().remove();
@@ -1283,9 +1282,9 @@ function initEditor() {
             }
         }
         if (e.keyCode == 191) {
-            var parts = $(this).val().split('/');
+            parts = $(this).val().split('/');
             for (var i = 0; i < parts.length; ++i) {
-                var value = parts[i];
+                value = parts[i];
                 if (i < parts.length - 1) {
                     if (value.length) {
                         $('<span class="section"><a href="#">' + value + '</a></span>').insertBefore($(this));
@@ -1298,9 +1297,9 @@ function initEditor() {
                 $(this)[0].setSelectionRange(0, 0);
             }
         }
-        var parts = [];
-        $('.breadcrumb span.section').each(function (i, element) {
-            element = $(element);
+        parts = [];
+        $('.breadcrumb span.section').each(function () {
+            var element = $(this);
             if (element.find('a').length) {
                 parts.push(element.find('a').text());
             } else {
@@ -1319,10 +1318,11 @@ function initEditor() {
     var markdownFileExts = $editArea.data("markdown-file-exts").split(",");
     var lineWrapExtensions = $editArea.data("line-wrap-extensions").split(",");
 
-    $editFilename.on("keyup", function (e) {
+    $editFilename.on("keyup", function () {
         var val = $editFilename.val(), m, mode, spec, extension, extWithDot, previewLink, dataUrl, apiCall;
         extension = extWithDot = "";
-        if (m = /.+\.([^.]+)$/.exec(val)) {
+        m = /.+\.([^.]+)$/.exec(val);
+        if (m) {
             extension = m[1];
             extWithDot = "." + extension;
         }
@@ -1684,15 +1684,6 @@ function buttonsClickOnEnter() {
     });
 }
 
-function hideWhenLostFocus(body, parent) {
-    $(document).click(function (e) {
-        var target = e.target;
-        if (!$(target).is(body) && !$(target).parents().is(parent)) {
-            $(body).hide();
-        }
-    });
-}
-
 function searchUsers() {
     var $searchUserBox = $('#search-user-box');
     $searchUserBox.search({
@@ -1701,7 +1692,7 @@ function searchUsers() {
             url: suburl + '/api/v1/users/search?q={query}',
             onResponse: function(response) {
                 var items = [];
-                $.each(response.data, function (i, item) {
+                $.each(response.data, function (_i, item) {
                     var title = item.login;
                     if (item.full_name && item.full_name.length > 0) {
                         title += ' (' + htmlEncode(item.full_name) + ')';
@@ -1728,7 +1719,7 @@ function searchRepositories() {
             url: suburl + '/api/v1/repos/search?q={query}&uid=' + $searchRepoBox.data('uid'),
             onResponse: function(response) {
                 var items = [];
-                $.each(response.data, function (i, item) {
+                $.each(response.data, function (_i, item) {
                     items.push({
                         title: item.full_name.split("/")[1],
                         description: item.full_name
@@ -1752,8 +1743,8 @@ function initCodeView() {
             deSelect();
         });
 
-        $(window).on('hashchange', function (e) {
-            var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/);
+        $(window).on('hashchange', function () {
+            var m = window.location.hash.match(/^#(L\d+)-(L\d+)$/);
             var $list = $('.code-view ol.linenums > li');
             var $first;
             if (m) {
@@ -1803,7 +1794,7 @@ function u2fSigned(resp) {
         contentType: "application/json; charset=utf-8",
     }).done(function(res){
         window.location.replace(res);
-    }).fail(function (xhr, textStatus) {
+    }).fail(function () {
         u2fError(1);
     });
 }
@@ -1821,7 +1812,7 @@ function u2fRegistered(resp) {
         success: function(){
             reload();
         },
-        fail: function (xhr, textStatus) {
+        fail: function () {
             u2fError(1);
         }
     });
@@ -1889,7 +1880,7 @@ function u2fRegisterRequest() {
                 }
                 u2fError(reason.metaData.code);
             });
-    }).fail(function(xhr, status, error) {
+    }).fail(function(xhr) {
         if(xhr.status === 409) {
             $("#nickname").closest("div.field").addClass("error");
         }
@@ -1962,7 +1953,7 @@ $(document).ready(function () {
     });
 
     // make table <tr> element clickable like a link
-    $('tr[data-href]').click(function(event) {
+    $('tr[data-href]').click(function() {
         window.location = $(this).data('href');
     });
 
@@ -2388,7 +2379,7 @@ function initVueComponents(){
                 var searchedURL = this.searchURL;
                 var searchedQuery = this.searchQuery;
 
-                $.getJSON(searchedURL, function(result, textStatus, request) {
+                $.getJSON(searchedURL, function(result, _textStatus, request) {
                     if (searchedURL == self.searchURL) {
                         self.repos = result.data;
                         var count = request.getResponseHeader('X-Total-Count');
@@ -2446,6 +2437,7 @@ function initVueApp() {
         },
     });
 }
+
 function timeAddManual() {
     $('.mini.modal')
         .modal({
@@ -2796,7 +2788,7 @@ function initTopicbar() {
         $.post(saveBtn.data('link'), {
             "_csrf": csrf,
             "topics": topics
-        }, function(data, textStatus, xhr){
+        }, function(_data, _textStatus, xhr){
             if (xhr.responseJSON.status === 'ok') {
                 viewDiv.children(".topic").remove();
                 if (topics.length) {
@@ -2873,14 +2865,14 @@ function initTopicbar() {
             this.attr("data-value", value).contents().first().replaceWith(value);
             return $(this);
         },
-        onAdd: function(addedValue, addedText, $addedChoice) {
+        onAdd: function(addedValue, _addedText, $addedChoice) {
             addedValue = addedValue.toLowerCase().trim();
             $($addedChoice).attr('data-value', addedValue);
             $($addedChoice).attr('data-text', addedValue);
         }
     });
 
-    $.fn.form.settings.rules.validateTopic = function(values, regExp) {
+    $.fn.form.settings.rules.validateTopic = function(_values, regExp) {
         var topics = topicDropdown.children('a.ui.label'),
             status = topics.length === 0 || topics.last().attr("data-value").match(regExp);
         if (!status) {
@@ -2981,7 +2973,7 @@ function initIssueList() {
                     var filteredResponse = {'success': true, 'results': []};
                     var currIssueId = $('#new-dependency-drop-list').data('issue-id');
                     // Parse the response from the api to work with our dropdown
-                    $.each(response, function(index, issue) {
+                    $.each(response, function(_i, issue) {
                         // Don't list current issue in the dependency list.
                         if(issue.id === currIssueId) {
                             return;