diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..a66b1330 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,32 @@ +name: Tests +on: [push, pull_request] +env: + CI: true + +jobs: + run: + name: Node ${{ matrix.node }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + node: [12] + + steps: + - name: Clone repository + uses: actions/checkout@v2 + + - name: Set Node.js version + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + + - run: node --version + - run: npm --version + + - name: Install npm dependencies + run: npm ci + + - name: Run tests + run: npm test diff --git a/.pullapprove.yml b/.pullapprove.yml deleted file mode 100644 index 42d3b2fb..00000000 --- a/.pullapprove.yml +++ /dev/null @@ -1,38 +0,0 @@ -version: 2 - -always_pending: - title_regex: '(WIP|wip)' - labels: - - wip - explanation: 'This PR is a work in progress...' - -group_defaults: - reset_on_push: - enabled: true - reject_value: -2 - approve_regex: '^(Approved|:shipit:|:\+1:|Engage|:taco:)' - reject_regex: '^(Rejected|:-1:|Borg)' - author_approval: - auto: true - - -groups: - development: - approve_by_comment: - enabled: true - conditions: - branches: - - devel - required: 2 - teams: - - approvers - - master: - approve_by_comment: - enabled: true - conditions: - branches: - - master - required: 4 - teams: - - approvers diff --git a/README.md b/README.md index 1caf7ef6..4c3684e3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Pi-hole Web interface

-Pi-hole[®](https://pi-hole.net/trademark-rules-and-brand-guidelines/)'s Web interface (based off of [AdminLTE](https://almsaeedstudio.com)) provides a central location to manage your Pi-hole and review the statistics generated by FTLDNS[™](https://pi-hole.net/trademark-rules-and-brand-guidelines/). +Pi-hole[®](https://pi-hole.net/trademark-rules-and-brand-guidelines/)'s Web interface (based off of [AdminLTE](https://github.com/ColorlibHQ/AdminLTE)) provides a central location to manage your Pi-hole and review the statistics generated by FTLDNS[™](https://pi-hole.net/trademark-rules-and-brand-guidelines/). - **Easy-to-interpret**: simple graphs and beautiful colors make Pi-hole's stats easy to understand - **Responsive**: looks great on desktop, tablets, and mobile devices @@ -13,7 +13,6 @@ Pi-hole[®](https://pi-hole.net/trademark-rules-and-brand-guidelines/)'s Web int - **Insightful**: use the query log, audit log, or long-term stats to gain insight into your networks activity --- -
# Installation diff --git a/api_FTL.php b/api_FTL.php index 571fe74b..f1a882d6 100644 --- a/api_FTL.php +++ b/api_FTL.php @@ -104,7 +104,8 @@ else foreach($return as $line) { $tmp = explode(" ",$line); - $top_queries[$tmp[2]] = intval($tmp[1]); + $domain = utf8_encode($tmp[2]); + $top_queries[$domain] = intval($tmp[1]); } if($_GET['topItems'] === "audit") @@ -125,10 +126,11 @@ else foreach($return as $line) { $tmp = explode(" ",$line); + $domain = utf8_encode($tmp[2]); if(count($tmp) > 3) - $top_ads[$tmp[2]." (".$tmp[3].")"] = intval($tmp[1]); + $top_ads[$domain." (".$tmp[3].")"] = intval($tmp[1]); else - $top_ads[$tmp[2]] = intval($tmp[1]); + $top_ads[$domain] = intval($tmp[1]); } $result = array('top_queries' => $top_queries, @@ -163,10 +165,14 @@ else foreach($return as $line) { $tmp = explode(" ",$line); + $clientip = utf8_encode($tmp[2]); if(count($tmp) > 3 && strlen($tmp[3]) > 0) - $top_clients[$tmp[3]."|".$tmp[2]] = intval($tmp[1]); + { + $clientname = utf8_encode($tmp[3]); + $top_clients[$clientname."|".$clientip] = intval($tmp[1]); + } else - $top_clients[$tmp[2]] = intval($tmp[1]); + $top_clients[$clientip] = intval($tmp[1]); } $result = array('top_sources' => $top_clients); @@ -195,10 +201,14 @@ else foreach($return as $line) { $tmp = explode(" ",$line); + $clientip = utf8_encode($tmp[2]); if(count($tmp) > 3 && strlen($tmp[3]) > 0) - $top_clients[$tmp[3]."|".$tmp[2]] = intval($tmp[1]); + { + $clientname = utf8_encode($tmp[3]); + $top_clients[$clientname."|".$clientip] = intval($tmp[1]); + } else - $top_clients[$tmp[2]] = intval($tmp[1]); + $top_clients[$clientip] = intval($tmp[1]); } $result = array('top_sources_blocked' => $top_clients); @@ -220,10 +230,14 @@ else foreach($return as $line) { $tmp = explode(" ",$line); + $forwardip = utf8_encode($tmp[2]); if(count($tmp) > 3 && strlen($tmp[3]) > 0) - $forward_dest[$tmp[3]."|".$tmp[2]] = floatval($tmp[1]); + { + $forwardname = utf8_encode($tmp[3]); + $forward_dest[$forwardname."|".$forwardip] = floatval($tmp[1]); + } else - $forward_dest[$tmp[2]] = floatval($tmp[1]); + $forward_dest[$forwardip] = floatval($tmp[1]); } $result = array('forward_destinations' => $forward_dest); @@ -238,6 +252,7 @@ else foreach($return as $ret) { $tmp = explode(": ",$ret); + // Reply cannot contain non-ASCII characters $querytypes[$tmp[0]] = floatval($tmp[1]); } @@ -253,6 +268,7 @@ else foreach($return as $ret) { $tmp = explode(": ",$ret); + // Reply cannot contain non-ASCII characters $cacheinfo[$tmp[0]] = floatval($tmp[1]); } @@ -301,6 +317,10 @@ else foreach($return as $line) { $tmp = explode(" ",$line); + // UTF-8 encode domain + $tmp[2] = utf8_encode($tmp[2]); + // UTF-8 encode client host name + $tmp[3] = utf8_encode($tmp[3]);; array_push($allQueries,$tmp); } @@ -311,7 +331,7 @@ else if(isset($_GET["recentBlocked"])) { sendRequestFTL("recentBlocked"); - die(getResponseFTL()[0]); + die(utf8_encode(getResponseFTL()[0])); unset($data); } @@ -323,13 +343,15 @@ else foreach($return as $line) { $tmp = explode(" ",$line); + $forwardip = utf8_encode($tmp[2]); if(count($tmp) > 3) { - $forward_dest[$tmp[3]."|".$tmp[2]] = floatval($tmp[1]); + $forwardname = utf8_encode($tmp[3]); + $forward_dest[$forwardname."|".$forwardip] = floatval($tmp[1]); } else { - $forward_dest[$tmp[2]] = floatval($tmp[1]); + $forward_dest[$forwardip] = floatval($tmp[1]); } } @@ -363,8 +385,8 @@ else { $tmp = explode(" ", $line); $client_names[] = array( - "name" => $tmp[0], - "ip" => $tmp[1] + "name" => utf8_encode($tmp[0]), + "ip" => utf8_encode($tmp[1]) ); } diff --git a/api_db.php b/api_db.php index 5195114e..99358589 100644 --- a/api_db.php +++ b/api_db.php @@ -8,6 +8,7 @@ $api = true; header('Content-type: application/json'); +require("scripts/pi-hole/php/database.php"); require("scripts/pi-hole/php/password.php"); require("scripts/pi-hole/php/auth.php"); check_cors(); @@ -48,51 +49,11 @@ function resolveHostname($clientip, $printIP) return $clientname; } -// Get posible non-standard location of FTL's database -$FTLsettings = parse_ini_file("/etc/pihole/pihole-FTL.conf"); -if(isset($FTLsettings["DBFILE"])) -{ - $DBFILE = $FTLsettings["DBFILE"]; -} -else -{ - $DBFILE = "/etc/pihole/pihole-FTL.db"; -} - // Needs package php5-sqlite, e.g. // sudo apt-get install php5-sqlite -function SQLite3_connect($trytoreconnect) -{ - global $DBFILE; - try - { - // connect to database - return new SQLite3($DBFILE, SQLITE3_OPEN_READONLY); - } - catch (Exception $exception) - { - // sqlite3 throws an exception when it is unable to connect, try to reconnect after 3 seconds - if($trytoreconnect) - { - sleep(3); - $db = SQLite3_connect(false); - } - } -} - -if(strlen($DBFILE) > 0) -{ - $db = SQLite3_connect(true); -} -else -{ - die("No database available"); -} -if(!$db) -{ - die("Error connecting to database"); -} +$QUERYDB = getQueriesDBFilename(); +$db = SQLite3_connect($QUERYDB); if(isset($_GET["network"]) && $auth) { @@ -100,7 +61,19 @@ if(isset($_GET["network"]) && $auth) $results = $db->query('SELECT * FROM network'); while($results !== false && $res = $results->fetchArray(SQLITE3_ASSOC)) + { + $id = $res["id"]; + // Empty array for holding the IP addresses + $res["ip"] = array(); + // Get IP addresses for this device + $network_addresses = $db->query("SELECT ip FROM network_addresses WHERE network_id = $id ORDER BY lastSeen DESC"); + while($network_addresses !== false && $ip = $network_addresses->fetchArray(SQLITE3_ASSOC)) + array_push($res["ip"],$ip["ip"]); + // UTF-8 encode host name and vendor + $res["name"] = utf8_encode($res["name"]); + $res["macVendor"] = utf8_encode($res["macVendor"]); array_push($network, $res); + } $data = array_merge($data, array('network' => $network)); } @@ -164,12 +137,15 @@ if (isset($_GET['getAllQueries']) && $auth) case 7: $query_type = "TXT"; break; + case 8: + $query_type = "NAPTR"; + break; default: $query_type = "UNKN"; break; } - - $allQueries[] = [$row[0], $query_type, $row[2], $c, $row[4]]; + // array: time type domain client status + $allQueries[] = [$row[0], $query_type, utf8_encode($row[2]), utf8_encode($c), $row[4]]; } } $result = array('data' => $allQueries); @@ -202,8 +178,8 @@ if (isset($_GET['topClients']) && $auth) if(!is_bool($results)) while ($row = $results->fetchArray()) { - - $c = resolveHostname($row[0],false); + // Try to resolve host name and convert to UTF-8 + $c = utf8_encode(resolveHostname($row[0],false)); if(array_key_exists($c, $clientnums)) { @@ -253,8 +229,8 @@ if (isset($_GET['topDomains']) && $auth) if(!is_bool($results)) while ($row = $results->fetchArray()) { - // Convert client to lower case - $c = strtolower($row[0]); + // Convert domain to lower case UTF-8 + $c = utf8_encode(strtolower($row[0])); if(array_key_exists($c, $domains)) { // Entry already exists, add to it (might appear multiple times due to mixed capitalization in the database) @@ -303,7 +279,7 @@ if (isset($_GET['topAds']) && $auth) if(!is_bool($results)) while ($row = $results->fetchArray()) { - $addomains[$row[0]] = intval($row[1]); + $addomains[utf8_encode($row[0])] = intval($row[1]); } $result = array('top_ads' => $addomains); $data = array_merge($data, $result); @@ -392,20 +368,28 @@ if (isset($_GET['getGraphData']) && $auth) // Parse the DB result into graph data, filling in missing interval sections with zero function parseDBData($results, $interval, $from, $until) { $data = array(); + $first_db_timestamp = -1; if(!is_bool($results)) { // Read in the data while($row = $results->fetchArray()) { // $data[timestamp] = value_in_this_interval $data[$row[0]] = intval($row[1]); + if($first_db_timestamp === -1) + $first_db_timestamp = intval($row[0]); } + } - // Fill the missing intervals with zero - // Advance in steps of interval - for($i = $from; $i < $until; $i += $interval) { - if(!array_key_exists($i, $data)) - $data[$i] = 0; - } + // It is unpredictable what the first timestamp returned by the database + // will be. This depends on live data. Hence, we re-align the FROM + // timestamp to avoid unaligned holes appearing as additional + // (incorrect) data points + $aligned_from = $from + (($first_db_timestamp - $from) % $interval); + + // Fill gaps in returned data + for($i = $aligned_from; $i < $until; $i += $interval) { + if(!array_key_exists($i, $data)) + $data[$i] = 0; } return $data; diff --git a/auditlog.php b/auditlog.php index 4f105a70..33ed04ac 100644 --- a/auditlog.php +++ b/auditlog.php @@ -68,14 +68,9 @@ -
-

Important: Note that black- and whitelisted domains are not automatically applied on this page to avoid restarting the DNS service too often. Instead, click on this button, to have the new settings become effective:

- -
- diff --git a/db_graph.php b/db_graph.php index f6fe1ebf..9a7030e0 100644 --- a/db_graph.php +++ b/db_graph.php @@ -32,7 +32,7 @@ $token = $_SESSION['token'];
- + diff --git a/db_lists.php b/db_lists.php index 014d0a74..13792277 100644 --- a/db_lists.php +++ b/db_lists.php @@ -33,7 +33,7 @@ $token = $_SESSION['token'];
- + diff --git a/db_queries.php b/db_queries.php index fd8e3a85..0035807f 100644 --- a/db_queries.php +++ b/db_queries.php @@ -33,7 +33,7 @@ $token = $_SESSION['token'];
- + @@ -45,34 +45,39 @@ $token = $_SESSION['token'];
-
+
- + +
+
+
-
+
- + +
+
+
-
+
- + +
+
+
-
+
- +
-
-
- +
-
-
- +
@@ -92,7 +97,7 @@ $token = $_SESSION['token'];

Queries Blocked

- +
@@ -105,7 +110,7 @@ $token = $_SESSION['token'];

Queries Blocked (Wildcards)

- +
@@ -118,7 +123,7 @@ $token = $_SESSION['token'];

Queries Total

- +
@@ -131,7 +136,7 @@ $token = $_SESSION['token'];

Queries Blocked

- +
diff --git a/debug.php b/debug.php index 9840331f..ccb139c7 100644 --- a/debug.php +++ b/debug.php @@ -1,4 +1,4 @@ -Generate debug log -

Upload debug log and provide token once finished

+

Upload debug log and provide token once finished

Once you click this button a debug log will be generated and can automatically be uploaded if we detect a working internet connection.

diff --git a/dns_records.php b/dns_records.php new file mode 100644 index 00000000..91f84618 --- /dev/null +++ b/dns_records.php @@ -0,0 +1,96 @@ + + + + + + +
+
+
+ +
+

+ Add a new domain/IP combination +

+
+ +
+
+
+ + +
+
+ + +
+
+
+ +
+
+
+ + + + + + +
+
+
+
+

+ List of local DNS domains +

+
+ +
+ + + + + + + + +
DomainIPAction
+ +
+ +
+ +
+
+ + + + diff --git a/gravity.php b/gravity.php index d86be424..b73cf514 100644 --- a/gravity.php +++ b/gravity.php @@ -15,7 +15,7 @@ @@ -89,7 +89,7 @@

Tools → Query Lists

- This function is useful to find out what list a domain appears on. Since we don't control what the third-parties put on the blocklists, you may find that a domain you normally visit stops working. If this is the case, you could run this command to scan for strings in the list of blocked domains and it will return the list the domain is found on. This proved useful a while back when the Mahakala list was adding apple.com and microsoft.com to their block list.

+ This function is useful to find out what list a domain appears on. Since we don't control what the third-parties put on the blocklists, you may find that a domain you normally visit stops working. If this is the case, you could run this command to scan for strings in the list of blocked domains and it will return the list the domain is found on. This proved useful a while back when the Mahakala list was adding apple.com and microsoft.com to their block list.

diff --git a/img/favicon.png b/img/favicon.png deleted file mode 100644 index 35dd8c98..00000000 Binary files a/img/favicon.png and /dev/null differ diff --git a/img/favicons/android-chrome-192x192.png b/img/favicons/android-chrome-192x192.png new file mode 100644 index 00000000..74da2e5d Binary files /dev/null and b/img/favicons/android-chrome-192x192.png differ diff --git a/img/favicons/android-chrome-512x512.png b/img/favicons/android-chrome-512x512.png new file mode 100644 index 00000000..6a6281f6 Binary files /dev/null and b/img/favicons/android-chrome-512x512.png differ diff --git a/img/favicons/apple-touch-icon.png b/img/favicons/apple-touch-icon.png new file mode 100644 index 00000000..1b4b7215 Binary files /dev/null and b/img/favicons/apple-touch-icon.png differ diff --git a/img/favicons/favicon-16x16.png b/img/favicons/favicon-16x16.png new file mode 100644 index 00000000..cd2773bf Binary files /dev/null and b/img/favicons/favicon-16x16.png differ diff --git a/img/favicons/favicon-32x32.png b/img/favicons/favicon-32x32.png new file mode 100644 index 00000000..92c1c601 Binary files /dev/null and b/img/favicons/favicon-32x32.png differ diff --git a/img/favicons/favicon.ico b/img/favicons/favicon.ico new file mode 100644 index 00000000..c603e12a Binary files /dev/null and b/img/favicons/favicon.ico differ diff --git a/img/favicons/manifest.json b/img/favicons/manifest.json new file mode 100644 index 00000000..a4c4defe --- /dev/null +++ b/img/favicons/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "Pi-hole Admin Console", + "short_name": "Pi-hole", + "icons": [ + { + "src": "android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#367fa9", + "background_color": "#367fa9", + "display": "standalone" +} diff --git a/img/favicons/mstile-150x150.png b/img/favicons/mstile-150x150.png new file mode 100644 index 00000000..2436d899 Binary files /dev/null and b/img/favicons/mstile-150x150.png differ diff --git a/img/favicons/safari-pinned-tab.svg b/img/favicons/safari-pinned-tab.svg new file mode 100644 index 00000000..ecbe5a9f --- /dev/null +++ b/img/favicons/safari-pinned-tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/logo.svg b/img/logo.svg index eeeec322..3955f31b 100644 --- a/img/logo.svg +++ b/img/logo.svg @@ -1 +1 @@ -NewVortex \ No newline at end of file +NewVortex \ No newline at end of file diff --git a/index.php b/index.php index f34a7171..78c1a464 100644 --- a/index.php +++ b/index.php @@ -32,7 +32,7 @@

---

- +
@@ -45,7 +45,7 @@

---

- +
@@ -58,7 +58,7 @@

---

- +
@@ -71,7 +71,7 @@

---

- +
@@ -82,7 +82,7 @@
-

Queries over last hours

+

Total queries over last hours

@@ -107,7 +107,7 @@
-

Clients (over time)

+

Client activity over last hours

@@ -129,10 +129,10 @@

Query Types

-
+
-
+
@@ -148,10 +148,10 @@

Queries answered by

-
+
-
+
diff --git a/list.php b/list.php deleted file mode 100644 index 5cbff9c7..00000000 --- a/list.php +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - -
- - - - - - - - - - - -
- - - - - - - - - - -

Exact blocking

- -
    - -

    Regex & Wildcard blocking

    -
      - - - - - diff --git a/network.php b/network.php index e92f0ef6..7c1f9b02 100644 --- a/network.php +++ b/network.php @@ -52,12 +52,12 @@ $token = $_SESSION['token']; - - - - - - + + + + + +
      just now
      ... to ...
      24 hours ago> 24 hours agoDevice does not use Pi-hole
      just now
      ... to ...
      24 hours ago> 24 hours agoDevice does not use Pi-hole
      diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..e88b1cc1 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4909 @@ +{ + "name": "AdminLTE", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "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", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.2.tgz", + "integrity": "sha512-B8emQA1qeKerqd1dmIsQYnXi+mmAzTB7flExjmy5X1aVAKFNNNDubkavwR13kR6JnpeLp3aLoJhwn9trWPAyFQ==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "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 + }, + "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 + }, + "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" + } + } + } + }, + "ansi-escapes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "boxen": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", + "integrity": "sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^2.4.2", + "cli-boxes": "^2.2.0", + "string-width": "^3.0.0", + "term-size": "^1.2.0", + "type-fest": "^0.3.0", + "widest-line": "^2.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "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 + }, + "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 + }, + "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" + } + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "buf-compare": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buf-compare/-/buf-compare-1.0.1.tgz", + "integrity": "sha1-/vKNqLgROgoNtEMLC2Rntpcws0o=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha1-jffHquUf02h06PjQW5GAvBGj/tc=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "cli-boxes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", + "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.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 + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "configstore": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", + "integrity": "sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-assert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/core-assert/-/core-assert-0.2.1.tgz", + "integrity": "sha1-+F4s+b/tKPdzzIs/pcW2m9wC/j8=", + "dev": true, + "requires": { + "buf-compare": "^1.0.0", + "is-error": "^2.2.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" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "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" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "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 + }, + "deep-strict-equal": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/deep-strict-equal/-/deep-strict-equal-0.2.0.tgz", + "integrity": "sha1-SgeBR6irV/ag1PVUckPNIvROtOQ=", + "dev": true, + "requires": { + "core-assert": "^0.2.0" + } + }, + "defer-to-connect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.1.tgz", + "integrity": "sha512-J7thop4u3mRTkYRQ+Vpfwy2G5Ehoy82I14+14W4YMDLKdWloI9gSzRbV30s/NckQGVJtPkWNcW4oMAUigTdqiQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", + "dev": true + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "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" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhance-visitors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/enhance-visitors/-/enhance-visitors-1.0.0.tgz", + "integrity": "sha1-qpRdBdpGVnKh69OP7i7T2oUY6Vo=", + "dev": true, + "requires": { + "lodash": "^4.13.1" + } + }, + "env-editor": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.1.tgz", + "integrity": "sha512-suh+Vm00GnPQgXpmONTkcUT9LgBSL6sJrRnJxbykT0j+ONjzmIS+1U3ne467ArdZN/42/npp+GnhtwkLQ+vUjw==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", + "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-ast-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-ast-utils/-/eslint-ast-utils-1.1.0.tgz", + "integrity": "sha512-otzzTim2/1+lVrlH19EfQQJEhVJSu0zOb9ygb3iapN6UlyaDtyRq4b5U1FuW0v1lRa9Fp/GJyHkSwm6NqABgCA==", + "dev": true, + "requires": { + "lodash.get": "^4.4.2", + "lodash.zip": "^4.2.0" + } + }, + "eslint-config-prettier": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.9.0.tgz", + "integrity": "sha512-k4E14HBtcLv0uqThaI6I/n1LEqROp8XaPu6SO9Z32u5NlGRC07Enu1Bh2KEFw4FNHbekH8yzbIU9kUGxbiGmCA==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + } + } + }, + "eslint-config-xo": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/eslint-config-xo/-/eslint-config-xo-0.27.2.tgz", + "integrity": "sha512-qEuZP0zNQkWpOdNZvWnfY2GNp1AZ33uXgeOXl4DN5YVLHFvekHbeSM2FFZ8A489fp1rCCColVRlJsYMf28o4DA==", + "dev": true + }, + "eslint-formatter-pretty": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eslint-formatter-pretty/-/eslint-formatter-pretty-2.1.1.tgz", + "integrity": "sha512-gWfagucSWBn82WxzwFloBTLAcwYDgnpAfiV5pQfyAV5YpZikuLflRU8nc3Ts9wnNvLhwk4blzb42/C495Yw7BA==", + "dev": true, + "requires": { + "ansi-escapes": "^3.1.0", + "chalk": "^2.1.0", + "eslint-rule-docs": "^1.1.5", + "log-symbols": "^2.0.0", + "plur": "^3.0.1", + "string-width": "^2.0.0", + "supports-hyperlinks": "^1.0.1" + }, + "dependencies": { + "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 + }, + "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 + }, + "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" + } + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz", + "integrity": "sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "eslint-plugin-ava": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-ava/-/eslint-plugin-ava-9.0.0.tgz", + "integrity": "sha512-mJqQ1wQ9pxBi5Pu+grrqjfuSLxiSSgnpa5p5vMdEpBqA9n9cUzSCv0xMZ/NkTMAj5ieOB3TWF8j+7C30Yiv4RA==", + "dev": true, + "requires": { + "deep-strict-equal": "^0.2.0", + "enhance-visitors": "^1.0.0", + "espree": "^6.0.0", + "espurify": "^2.0.0", + "import-modules": "^1.1.0", + "pkg-dir": "^4.2.0", + "resolve-from": "^5.0.0" + } + }, + "eslint-plugin-es": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz", + "integrity": "sha512-f6fceVtg27BR02EYnBhgWLFQfK6bN4Ll0nQFrBHOlCsAyxeZkn0NHns5O0YZOPrV1B3ramd6cgFwaoFLcSkwEQ==", + "dev": true, + "requires": { + "eslint-utils": "^1.4.2", + "regexpp": "^3.0.0" + }, + "dependencies": { + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true + } + } + }, + "eslint-plugin-eslint-comments": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.1.2.tgz", + "integrity": "sha512-QexaqrNeteFfRTad96W+Vi4Zj1KFbkHHNMMaHZEYcovKav6gdomyGzaxSDSL3GoIyUOo078wRAdYlu1caiauIQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "dependencies": { + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.19.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz", + "integrity": "sha512-x68131aKoCZlCae7rDXKSAQmbT5DQuManyXo2sK6fJJ0aK5CWAkv6A6HJZGgqC8IhjQxYPgo6/IY4Oz8AFsbBw==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.1", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-no-use-extend-native": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-use-extend-native/-/eslint-plugin-no-use-extend-native-0.4.1.tgz", + "integrity": "sha512-tDkHM0kvxU0M2TpLRKGfFrpWXctFdTDY7VkiDTLYDaX90hMSJKkr/FiWThEXvKV0Dvffut2Z0B9Y7+h/k6suiA==", + "dev": true, + "requires": { + "is-get-set-prop": "^1.0.0", + "is-js-type": "^2.0.0", + "is-obj-prop": "^1.0.0", + "is-proto-prop": "^2.0.0" + } + }, + "eslint-plugin-node": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz", + "integrity": "sha512-1CSyM/QCjs6PXaT18+zuAXsjXGIGo5Rw630rSKwokSs2jrYURQc4R5JZpoanNCqwNmepg+0eZ9L7YiRUJb8jiQ==", + "dev": true, + "requires": { + "eslint-plugin-es": "^2.0.0", + "eslint-utils": "^1.4.2", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + } + } + }, + "eslint-plugin-prettier": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz", + "integrity": "sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-promise": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "dev": true + }, + "eslint-plugin-unicorn": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-12.1.0.tgz", + "integrity": "sha512-DkPRrjaZaKa8GDjEyWGms/sqp2DcmVCcbwVi9WQXwN6+Sn0/joTC14SfA+BsCuxTaGPRm/7wa8NC8o5mNDyZpQ==", + "dev": true, + "requires": { + "ci-info": "^2.0.0", + "clean-regexp": "^1.0.0", + "eslint-ast-utils": "^1.1.0", + "eslint-template-visitor": "^1.0.0", + "import-modules": "^2.0.0", + "lodash.camelcase": "^4.3.0", + "lodash.defaultsdeep": "^4.6.1", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.topairs": "^4.3.0", + "lodash.upperfirst": "^4.3.1", + "read-pkg-up": "^7.0.0", + "regexpp": "^3.0.0", + "reserved-words": "^0.1.2", + "safe-regex": "^2.0.2", + "semver": "^6.3.0" + }, + "dependencies": { + "import-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-modules/-/import-modules-2.0.0.tgz", + "integrity": "sha512-iczM/v9drffdNnABOKwj0f9G3cFDon99VcG1mxeBsdqnbd+vnQ5c2uAiCHNQITqFTOPaEvwg3VjoWCur0uHLEw==", + "dev": true + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true + } + } + }, + "eslint-rule-docs": { + "version": "1.1.172", + "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.172.tgz", + "integrity": "sha512-WgrhDcKxp8MdC9RRviS3BxXN4h20jHfSlXoOpTWJWxsWBHZ2nsTXhBXmRwMZJBj5elnZPPPMFN+z4yJMBsVwYA==", + "dev": true + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-template-visitor": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-template-visitor/-/eslint-template-visitor-1.1.0.tgz", + "integrity": "sha512-Lmy6QVlmFiIGl5fPi+8ACnov3sare+0Ouf7deJAGGhmUfeWJ5fVarELUxZRpsZ9sHejiJUq8626d0dn9uvcZTw==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.1", + "multimap": "^1.0.2" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, + "requires": { + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.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 + }, + "espurify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/espurify/-/espurify-2.0.1.tgz", + "integrity": "sha512-7w/dUrReI/QbJFHRwfomTlkQOXaB1NuCrBRn5Y26HXn5gvh18/19AgLbayVrNxXQfkckvgrJloWyvZDuJ7dhEA==", + "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.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "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", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "dependencies": { + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "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", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.2.0.tgz", + "integrity": "sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.0", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "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-set-props": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-set-props/-/get-set-props-0.1.0.tgz", + "integrity": "sha1-mYR1wXhEVobQsyJG2l3428++jqM=", + "dev": true + }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "globals": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "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.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "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 + } + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "import-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/import-modules/-/import-modules-1.1.0.tgz", + "integrity": "sha1-dI23nFzEK7lwHvq0JPiU5yYA6dw=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.1.tgz", + "integrity": "sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, + "irregular-plurals": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", + "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-error": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", + "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-get-set-prop": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-get-set-prop/-/is-get-set-prop-1.0.0.tgz", + "integrity": "sha1-JzGHfk14pqae3M5rudaLB3nnYxI=", + "dev": true, + "requires": { + "get-set-props": "^0.1.0", + "lowercase-keys": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-js-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-js-type/-/is-js-type-2.0.0.tgz", + "integrity": "sha1-c2FwBtZZtOtHKbunR9KHgt8PfiI=", + "dev": true, + "requires": { + "js-types": "^1.0.0" + } + }, + "is-npm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", + "integrity": "sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-obj-prop": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-obj-prop/-/is-obj-prop-1.0.0.tgz", + "integrity": "sha1-s03nnEULjXxzqyzfZ9yHWtuF+A4=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0", + "obj-props": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-proto-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-proto-prop/-/is-proto-prop-2.0.0.tgz", + "integrity": "sha512-jl3NbQ/fGLv5Jhan4uX+Ge9ohnemqyblWVVCpAvtTQzNFvV2xhJq+esnkIbYQ9F1nITXoLfDDQLp7LBw/zzncg==", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0", + "proto-props": "^2.0.0" + } + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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-types": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/js-types/-/js-types-1.0.0.tgz", + "integrity": "sha1-0kLmSU7Vcq08koCfyL7X92h8vwM=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-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 + }, + "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 + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.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" + } + }, + "line-column-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/line-column-path/-/line-column-path-2.0.0.tgz", + "integrity": "sha512-nz3A+vi4bElhwd62E9+Qk/f9BDYLSzD/4Hy1rir0I4GnMxSTezSymzANyph5N1PgRZ3sSbA+yR5hOuXxc71a0Q==", + "dev": true, + "requires": { + "type-fest": "^0.4.1" + }, + "dependencies": { + "type-fest": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", + "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", + "dev": true + } + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", + "dev": true + }, + "lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true + }, + "lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40=", + "dev": true + }, + "lodash.topairs": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.topairs/-/lodash.topairs-4.3.0.tgz", + "integrity": "sha1-O23qo31g+xFnE8RsXxfqGQ7EjWQ=", + "dev": true + }, + "lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984=", + "dev": true + }, + "lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "meow": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", + "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0", + "yargs-parser": "^10.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + } + } + }, + "merge2": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + }, + "dependencies": { + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + } + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "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.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multimap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multimap/-/multimap-1.1.0.tgz", + "integrity": "sha512-0ZIR9PasPxGXmRsEF8jsDzndzHDj7tIav+JUmvIFB/WHswliFnquxECT/De7GR4yg99ky/NlRKJT82G1y271bw==", + "dev": true + }, + "multimatch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", + "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + } + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "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 + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "obj-props": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/obj-props/-/obj-props-1.2.0.tgz", + "integrity": "sha512-ZYpJyCe7O4rhNxB/2SZy8ADJww8RSRBdG36a4MWWq7JwILGJ1m61B90QJtxwDDNA0KzyR8V12Wikpjuux7Gl9Q==", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "open-editor": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/open-editor/-/open-editor-2.0.1.tgz", + "integrity": "sha512-B3KdD7Pl8jYdpBSBBbdYaqVUI3whQjLl1G1+CvhNc8+d7GzKRUq+VuCIx1thxGiqD2oBGRvsZz7QWrBsFP2yVA==", + "dev": true, + "requires": { + "env-editor": "^0.4.0", + "line-column-path": "^2.0.0", + "open": "^6.2.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "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 + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + } + }, + "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" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-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-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-conf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "plur": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", + "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", + "dev": true, + "requires": { + "irregular-plurals": "^2.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proto-props": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/proto-props/-/proto-props-2.0.0.tgz", + "integrity": "sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ==", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "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 + }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + } + } + }, + "regexp-tree": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.17.tgz", + "integrity": "sha512-UnOJjFS/EPZmfISmYx+0PcDtPzyFKTe+cZTS5sM5hifnRUDRxoB1j4DAmGwqzxjwBGlwOkGfb2cDGHtjuEwqoA==", + "dev": true + }, + "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 + }, + "registry-auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", + "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", + "dev": true, + "requires": { + "rc": "^1.2.8", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "reserved-words": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.2.tgz", + "integrity": "sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE=", + "dev": true + }, + "resolve": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", + "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.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.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + }, + "safe-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", + "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", + "dev": true, + "requires": { + "regexp-tree": "~0.1.1" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "^5.0.3" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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" + }, + "dependencies": { + "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 + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "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" + }, + "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-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + } + } + }, + "supports-hyperlinks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz", + "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==", + "dev": true, + "requires": { + "has-flag": "^2.0.0", + "supports-color": "^5.0.0" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + } + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "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 + }, + "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 + }, + "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" + } + } + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "^0.7.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 + }, + "the-argv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/the-argv/-/the-argv-1.0.0.tgz", + "integrity": "sha1-AIRwUAVzDdhNt1UlPJMa45jblSI=", + "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", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + } + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "update-notifier": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz", + "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==", + "dev": true, + "requires": { + "boxen": "^3.0.0", + "chalk": "^2.0.1", + "configstore": "^4.0.0", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.1.0", + "is-npm": "^3.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "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" + } + }, + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "requires": { + "string-width": "^2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "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" + } + } + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "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" + } + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "write-json-file": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-2.3.0.tgz", + "integrity": "sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8=", + "dev": true, + "requires": { + "detect-indent": "^5.0.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "pify": "^3.0.0", + "sort-keys": "^2.0.0", + "write-file-atomic": "^2.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "write-pkg": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-3.2.0.tgz", + "integrity": "sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw==", + "dev": true, + "requires": { + "sort-keys": "^2.0.0", + "write-json-file": "^2.2.0" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, + "xo": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/xo/-/xo-0.25.3.tgz", + "integrity": "sha512-125on+kPp6oi+EfoAajJ58cGLxIurZqWrehhdqoApWXpano9GL5D0ElcSlbG7UeYAfmNSwKJGTxHoLsHLhrZqg==", + "dev": true, + "requires": { + "arrify": "^2.0.1", + "debug": "^4.1.0", + "eslint": "^6.4.0", + "eslint-config-prettier": "^6.3.0", + "eslint-config-xo": "^0.27.1", + "eslint-formatter-pretty": "^2.0.0", + "eslint-plugin-ava": "^9.0.0", + "eslint-plugin-eslint-comments": "^3.0.1", + "eslint-plugin-import": "^2.18.2", + "eslint-plugin-no-use-extend-native": "^0.4.0", + "eslint-plugin-node": "^10.0.0", + "eslint-plugin-prettier": "^3.1.1", + "eslint-plugin-promise": "^4.0.0", + "eslint-plugin-unicorn": "^12.0.0", + "find-cache-dir": "^3.0.0", + "get-stdin": "^7.0.0", + "globby": "^9.0.0", + "has-flag": "^4.0.0", + "lodash.isequal": "^4.5.0", + "lodash.mergewith": "^4.6.2", + "meow": "^5.0.0", + "multimatch": "^4.0.0", + "open-editor": "^2.0.1", + "path-exists": "^4.0.0", + "pkg-conf": "^3.1.0", + "prettier": "^1.15.2", + "resolve-cwd": "^3.0.0", + "resolve-from": "^5.0.0", + "semver": "^6.3.0", + "slash": "^3.0.0", + "update-notifier": "^3.0.1", + "xo-init": "^0.7.0" + } + }, + "xo-init": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/xo-init/-/xo-init-0.7.0.tgz", + "integrity": "sha512-mrrCKMu52vz0u2tiOl8DoG709pBtnSp58bb4/j58a4jeXjrb1gV7dxfOBjOlXitYtfW2QnlxxxfAojoFcpynDg==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "execa": "^0.9.0", + "has-yarn": "^1.0.0", + "minimist": "^1.1.3", + "path-exists": "^3.0.0", + "read-pkg-up": "^3.0.0", + "the-argv": "^1.0.0", + "write-pkg": "^3.1.0" + }, + "dependencies": { + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", + "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "has-yarn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-1.0.0.tgz", + "integrity": "sha1-ieJdtgS3Jcj1l2//Ct3JIbgopac=", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + } + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..39e04aed --- /dev/null +++ b/package.json @@ -0,0 +1,65 @@ +{ + "name": "AdminLTE", + "version": "1.0.0", + "private": true, + "description": "", + "repository": { + "type": "git", + "url": "git+https://github.com/pi-hole/AdminLTE.git" + }, + "keywords": [], + "author": "", + "license": "EUPL-1.2", + "bugs": { + "url": "https://github.com/pi-hole/AdminLTE/issues" + }, + "homepage": "https://github.com/pi-hole/AdminLTE#readme", + "scripts": { + "xo": "xo", + "xo:fix": "npm run xo -- --fix", + "test": "npm run xo" + }, + "devDependencies": { + "xo": "^0.25.3" + }, + "prettier": { + "bracketSpacing": true, + "printWidth": 100, + "singleQuote": false, + "trailingComma": "none" + }, + "xo": { + "space": 2, + "envs": [ + "browser", + "jquery" + ], + "parserOptions": { + "ecmaVersion": 3, + "sourceType": "script" + }, + "esnext": false, + "prettier": true, + "ignores": [ + "**/vendor/**" + ], + "rules": { + "camelcase": "off", + "capitalized-comments": "off", + "new-cap": "off", + "no-alert": "off", + "no-negated-condition": "off", + "one-var": "off", + "radix": "off", + "spaced-comment": "off", + "unicorn/explicit-length-check": "off", + "unicorn/filename-case": "off", + "unicorn/no-for-loop": "off", + "unicorn/no-zero-fractions": "off", + "unicorn/prefer-includes": "off", + "unicorn/prefer-node-append": "off", + "unicorn/prefer-query-selector": "off", + "unicorn/prefer-string-slice": "off" + } + } +} diff --git a/queries.php b/queries.php index 51c543e6..20c65305 100644 --- a/queries.php +++ b/queries.php @@ -155,7 +155,7 @@ if(strlen($showing) > 0) -
      +
      diff --git a/scripts/pi-hole/js/auditlog.js b/scripts/pi-hole/js/auditlog.js index 95c7fc3d..3850b5de 100644 --- a/scripts/pi-hole/js/auditlog.js +++ b/scripts/pi-hole/js/auditlog.js @@ -1,11 +1,12 @@ /* Pi-hole: A black hole for Internet advertisements -* (c) 2017 Pi-hole, LLC (https://pi-hole.net) -* Network-wide ad blocking via your own hardware. -* -* This file is copyright under the latest version of the EUPL. -* Please see LICENSE file for your rights under this license. */ + * (c) 2017 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ + // Define global variables -var timeLineChart, queryTypeChart, forwardDestinationChart, auditList = [], auditTimeout; +var auditTimeout = null; // Credit: http://stackoverflow.com/questions/1787322/htmlspecialchars-equivalent-in-javascript/4835406#4835406 function escapeHtml(text) { @@ -13,124 +14,145 @@ function escapeHtml(text) { "&": "&", "<": "<", ">": ">", - "\"": """, - "\'": "'" + '"': """, + "'": "'" }; - return text.replace(/[&<>"']/g, function(m) { return map[m]; }); + return text.replace(/[&<>"']/g, function(m) { + return map[m]; + }); } function updateTopLists() { - $.getJSON("api.php?topItems=audit", function(data) { + $.getJSON("api.php?topItems=audit", function(data) { + if ("FTLnotrunning" in data) { + return; + } - if("FTLnotrunning" in data) - { - return; + // Clear tables before filling them with data + $("#domain-frequency td") + .parent() + .remove(); + $("#ad-frequency td") + .parent() + .remove(); + var domaintable = $("#domain-frequency").find("tbody:last"); + var adtable = $("#ad-frequency").find("tbody:last"); + var url, domain; + for (domain in data.top_queries) { + if (Object.prototype.hasOwnProperty.call(data.top_queries, domain)) { + // Sanitize domain + domain = escapeHtml(domain); + url = '' + domain + ""; + domaintable.append( + "" + + url + + " " + + data.top_queries[domain] + + ' ' + ); + } + } + + for (domain in data.top_ads) { + if (Object.prototype.hasOwnProperty.call(data.top_ads, domain)) { + var input = domain.split(" "); + // Sanitize domain + var printdomain = escapeHtml(input[0]); + if (input.length > 1) { + url = + '' + + printdomain + + " (wildcard blocked)"; + adtable.append( + "" + + url + + " " + + data.top_ads[domain] + + ' ' + ); + } else { + url = '' + printdomain + ""; + adtable.append( + "" + + url + + " " + + data.top_ads[domain] + + ' ' + ); } + } + } - // Clear tables before filling them with data - $("#domain-frequency td").parent().remove(); - $("#ad-frequency td").parent().remove(); - var domaintable = $("#domain-frequency").find("tbody:last"); - var adtable = $("#ad-frequency").find("tbody:last"); - var url, domain, percentage; - for (domain in data.top_queries) { - if ({}.hasOwnProperty.call(data.top_queries,domain)){ - // Sanitize domain - domain = escapeHtml(domain); - url = ""+domain+""; - percentage = data.top_queries[domain] / data.dns_queries_today * 100; - domaintable.append(" " + url + - " " + data.top_queries[domain] + " "); - } - } + $("#domain-frequency .overlay").hide(); + $("#ad-frequency .overlay").hide(); + // Update top lists data every ten seconds + // Updates are also triggered by button actions + // and reset the running timer + if (auditTimeout !== null) { + window.clearTimeout(auditTimeout); + } - for (domain in data.top_ads) { - if ({}.hasOwnProperty.call(data.top_ads,domain)){ - var input = domain.split(" "); - // Sanitize domain - var printdomain = escapeHtml(input[0]); - if(input.length > 1) - { - url = ""+printdomain+" (wildcard blocked)"; - adtable.append(" " + url + - " " + data.top_ads[domain] + " "); - } - else - { - url = ""+printdomain+""; - adtable.append(" " + url + - " " + data.top_ads[domain] + " "); - } - } - } - - $("#domain-frequency .overlay").hide(); - $("#ad-frequency .overlay").hide(); - // Update top lists data every second - setTimeout(updateTopLists, 1000); - }); + auditTimeout = setTimeout(updateTopLists, 10000); + }); } +function add(domain, list) { + var token = $("#token").text(); + $.ajax({ + url: "scripts/pi-hole/php/add.php", + method: "post", + data: { domain: domain, list: list, token: token }, + success: function() { + updateTopLists(); + }, + error: function(jqXHR, exception) { + console.log(exception); + } + }); +} -function add(domain,list) { - var token = $("#token").html(); - $.ajax({ - url: "scripts/pi-hole/php/add.php", - method: "post", - data: {"domain":domain, "list":list, "token":token, "auditlog":1} - }); +function blacklistUrl(url) { + // We add to audit last as it will reload the table on success + add(url, "black"); + add(url, "audit"); +} + +function whitelistUrl(url) { + // We add to audit last as it will reload the table on success + add(url, "white"); + add(url, "audit"); +} + +function auditUrl(url) { + add(url, "audit"); } $(document).ready(function() { + // Pull in data via AJAX + updateTopLists(); - // Pull in data via AJAX - updateTopLists(); - - $("#domain-frequency tbody").on( "click", "button", function () { - var url = ($(this).parents("tr"))[0].innerText.split(" ")[0]; - if($(this).context.innerText === " Blacklist") - { - add(url,"black"); - $("#gravityBtn").prop("disabled", false); - } - else - { - auditUrl(url); - } - }); - - $("#ad-frequency tbody").on( "click", "button", function () { - var url = ($(this).parents("tr"))[0].innerText.split(" ")[0].split(" ")[0]; - if($(this).context.innerText === " Whitelist") - { - add(url,"white"); - $("#gravityBtn").prop("disabled", false); - } - else - { - auditUrl(url); - } - }); -}); - -function auditUrl(url) { - if (auditList.indexOf(url) > -1) { - return; + $("#domain-frequency tbody").on("click", "button", function() { + var url = $(this) + .parents("tr")[0] + .textContent.split(" ")[0]; + if ($(this).context.textContent === " Blacklist") { + blacklistUrl(url); + } else { + auditUrl(url); } - if (auditTimeout) { - clearTimeout(auditTimeout); + }); + + $("#ad-frequency tbody").on("click", "button", function() { + var url = $(this) + .parents("tr")[0] + .textContent.split(" ")[0]; + if ($(this).context.textContent === " Whitelist") { + whitelistUrl(url); + } else { + auditUrl(url); } - auditList.push(url); - // wait 3 seconds to see if more domains need auditing - // and batch them all into a single request - auditTimeout = setTimeout(function() { - add(auditList.join(' '), "audit"); - auditList = []; - }, 3000); -} - - -$("#gravityBtn").on("click", function() { - window.location.replace("gravity.php?go"); + }); }); diff --git a/scripts/pi-hole/js/customdns.js b/scripts/pi-hole/js/customdns.js new file mode 100644 index 00000000..8d9b7f3c --- /dev/null +++ b/scripts/pi-hole/js/customdns.js @@ -0,0 +1,110 @@ +/* Pi-hole: A black hole for Internet advertisements + * (c) 2017 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ + +var table; + +function showAlert(type, message) { + var alertElement = null; + var messageElement = null; + + switch (type) { + case "info": + alertElement = $("#alInfo"); + break; + case "success": + alertElement = $("#alSuccess"); + break; + case "warning": + alertElement = $("#alWarning"); + messageElement = $("#warn"); + break; + case "error": + alertElement = $("#alFailure"); + messageElement = $("#err"); + break; + default: + return; + } + + if (messageElement !== null) messageElement.html(message); + + alertElement.fadeIn(200); + alertElement.delay(8000).fadeOut(2000); +} + +$(document).ready(function() { + $("#btnAdd").on("click", addCustomDNS); + + table = $("#customDNSTable").DataTable({ + ajax: "scripts/pi-hole/php/customdns.php?action=get", + columns: [{}, {}, { orderable: false, searchable: false }], + columnDefs: [ + { + targets: 2, + render: function(data, type, row) { + return ( + '" + ); + } + } + ], + drawCallback: function() { + $(".deleteCustomDNS").on("click", deleteCustomDNS); + } + }); +}); + +function addCustomDNS() { + var ip = $("#ip").val(); + var domain = $("#domain").val(); + + showAlert("info"); + $.ajax({ + url: "scripts/pi-hole/php/customdns.php", + method: "post", + dataType: "json", + data: { action: "add", ip: ip, domain: domain }, + success: function(response) { + if (response.success) { + showAlert("success"); + table.ajax.reload(); + } else showAlert("error", response.message); + }, + error: function() { + showAlert("error", "Error while adding this custom DNS entry"); + } + }); +} + +function deleteCustomDNS() { + var ip = $(this).attr("data-ip"); + var domain = $(this).attr("data-domain"); + + showAlert("info"); + $.ajax({ + url: "scripts/pi-hole/php/customdns.php", + method: "post", + dataType: "json", + data: { action: "delete", domain: domain, ip: ip }, + success: function(response) { + if (response.success) { + showAlert("success"); + table.ajax.reload(); + } else showAlert("error", response.message); + }, + error: function(jqXHR, exception) { + showAlert("error", "Error while deleting this custom DNS entry"); + console.log(exception); + } + }); +} diff --git a/scripts/pi-hole/js/db_graph.js b/scripts/pi-hole/js/db_graph.js index 9699d325..590788d0 100644 --- a/scripts/pi-hole/js/db_graph.js +++ b/scripts/pi-hole/js/db_graph.js @@ -1,81 +1,97 @@ /* Pi-hole: A black hole for Internet advertisements -* (c) 2017 Pi-hole, LLC (https://pi-hole.net) -* Network-wide ad blocking via your own hardware. -* -* This file is copyright under the latest version of the EUPL. -* Please see LICENSE file for your rights under this license. */ + * (c) 2017 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ -/*global - moment -*/ +/* global Chart:false, moment:false */ var start__ = moment().subtract(6, "days"); -var from = moment(start__).utc().valueOf()/1000; +var from = + moment(start__) + .utc() + .valueOf() / 1000; var end__ = moment(); -var until = moment(end__).utc().valueOf()/1000; +var until = + moment(end__) + .utc() + .valueOf() / 1000; +var interval = 0; var timeoutWarning = $("#timeoutWarning"); var dateformat = "MMMM Do YYYY, HH:mm"; -$(function () { - $("#querytime").daterangepicker( +$(function() { + $("#querytime").daterangepicker( { - timePicker: true, timePickerIncrement: 15, + timePicker: true, + timePickerIncrement: 15, locale: { format: dateformat }, - startDate: start__, endDate: end__, + startDate: start__, + endDate: end__, ranges: { - "Today": [moment().startOf("day"), moment()], - "Yesterday": [moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day")], + Today: [moment().startOf("day"), moment()], + Yesterday: [ + moment() + .subtract(1, "days") + .startOf("day"), + moment() + .subtract(1, "days") + .endOf("day") + ], "Last 7 Days": [moment().subtract(6, "days"), moment()], "Last 30 Days": [moment().subtract(29, "days"), moment()], "This Month": [moment().startOf("month"), moment()], - "Last Month": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")], + "Last Month": [ + moment() + .subtract(1, "month") + .startOf("month"), + moment() + .subtract(1, "month") + .endOf("month") + ], "This Year": [moment().startOf("year"), moment()], "All Time": [moment(0), moment()] }, - "opens": "center", "showDropdowns": true, - "autoUpdateInput": false + opens: "center", + showDropdowns: true, + autoUpdateInput: false }, - function (startt, endt) { - from = moment(startt).utc().valueOf()/1000; - until = moment(endt).utc().valueOf()/1000; - }); - - + function(startt, endt) { + from = + moment(startt) + .utc() + .valueOf() / 1000; + until = + moment(endt) + .utc() + .valueOf() / 1000; + } + ); }); -// Credit: http://stackoverflow.com/questions/1787322/htmlspecialchars-equivalent-in-javascript/4835406#4835406 -function escapeHtml(text) { - var map = { - "&": "&", - "<": "<", - ">": ">", - "\"": """, - "\'": "'" - }; - - return text.replace(/[&<>"']/g, function(m) { return map[m]; }); -} - function padNumber(num) { - return ("00" + num).substr(-2,2); + return ("00" + num).substr(-2, 2); } // Helper function needed for converting the Objects to Arrays -function objectToArray(p){ - var keys = Object.keys(p); - keys.sort(function(a, b) { - return a - b; - }); +function objectToArray(p) { + var keys = Object.keys(p); + keys.sort(function(a, b) { + return a - b; + }); - var arr = [], idx = []; - for (var i = 0; i < keys.length; i++) { - arr.push(p[keys[i]]); - idx.push(keys[i]); - } - return [idx,arr]; + var arr = [], + idx = []; + for (var i = 0; i < keys.length; i++) { + arr.push(p[keys[i]]); + idx.push(keys[i]); + } + + return [idx, arr]; } var timeLineChart; @@ -85,187 +101,271 @@ function compareNumbers(a, b) { } function updateQueriesOverTime() { - $("#queries-over-time .overlay").show(); - timeoutWarning.show(); - $.getJSON("api_db.php?getGraphData&from="+from+"&until="+until, function(data) { + $("#queries-over-time .overlay").show(); + timeoutWarning.show(); - // convert received objects to arrays - data.domains_over_time = objectToArray(data.domains_over_time); - data.ads_over_time = objectToArray(data.ads_over_time); - // Remove possibly already existing data - timeLineChart.data.labels = []; - timeLineChart.data.datasets[0].data = []; - timeLineChart.data.datasets[1].data = []; + // Compute interval to obtain about 200 values + var num = 200; + interval = (until - from) / num; + // Default displaying axis scaling + timeLineChart.options.scales.xAxes[0].time.unit = "hour"; - var dates = [], hour; + if (num * interval >= 6 * 29 * 24 * 60 * 60) { + // If the requested data is more than 3 months, set ticks interval to quarterly + timeLineChart.options.scales.xAxes[0].time.unit = "quarter"; + } else if (num * interval >= 3 * 29 * 24 * 60 * 60) { + // If the requested data is more than 3 months, set ticks interval to months + timeLineChart.options.scales.xAxes[0].time.unit = "month"; + } - for (hour in data.domains_over_time[0]) { - if ({}.hasOwnProperty.call(data.domains_over_time[0], hour)) { - dates.push(parseInt(data.domains_over_time[0][hour])); - } + if (num * interval >= 29 * 24 * 60 * 60) { + // If the requested data is more than 1 month, set ticks interval to weeks + timeLineChart.options.scales.xAxes[0].time.unit = "week"; + } else if (num * interval >= 6 * 24 * 60 * 60) { + // If the requested data is more than 1 week, set ticks interval to days + timeLineChart.options.scales.xAxes[0].time.unit = "day"; + } + + $.getJSON( + "api_db.php?getGraphData&from=" + from + "&until=" + until + "&interval=" + interval, + function(data) { + // convert received objects to arrays + data.domains_over_time = objectToArray(data.domains_over_time); + data.ads_over_time = objectToArray(data.ads_over_time); + // Remove possibly already existing data + timeLineChart.data.labels = []; + timeLineChart.data.datasets[0].data = []; + timeLineChart.data.datasets[1].data = []; + + var dates = [], + hour; + + for (hour in data.domains_over_time[0]) { + if (Object.prototype.hasOwnProperty.call(data.domains_over_time[0], hour)) { + dates.push(parseInt(data.domains_over_time[0][hour])); } + } - for (hour in data.ads_over_time[0]) { - if ({}.hasOwnProperty.call(data.ads_over_time[0], hour)) { - if(!dates.includes(parseInt(data.ads_over_time[0][hour]))) - { - dates.push(parseInt(data.ads_over_time[0][hour])); - } - } + for (hour in data.ads_over_time[0]) { + if (Object.prototype.hasOwnProperty.call(data.ads_over_time[0], hour)) { + if (dates.indexOf(parseInt(data.ads_over_time[0][hour])) === -1) { + dates.push(parseInt(data.ads_over_time[0][hour])); + } } + } - dates.sort(compareNumbers); + dates.sort(compareNumbers); - // Add data for each hour that is available - for (hour in dates) { - if ({}.hasOwnProperty.call(dates, hour)) { - var d, dom = 0, ads = 0; - d = new Date(1000*dates[hour]); + // Add data for each hour that is available + for (hour in dates) { + if (Object.prototype.hasOwnProperty.call(dates, hour)) { + var date, + total = 0, + blocked = 0; + date = new Date(1000 * dates[hour]); - var idx = data.domains_over_time[0].indexOf(dates[hour].toString()); - if (idx > -1) - { - dom = data.domains_over_time[1][idx]; - } + var idx = data.domains_over_time[0].indexOf(dates[hour].toString()); + if (idx > -1) { + total = data.domains_over_time[1][idx]; + } - idx = data.ads_over_time[0].indexOf(dates[hour].toString()); - if (idx > -1) - { - ads = data.ads_over_time[1][idx]; - } + idx = data.ads_over_time[0].indexOf(dates[hour].toString()); + if (idx > -1) { + blocked = data.ads_over_time[1][idx]; + } - timeLineChart.data.labels.push(d); - timeLineChart.data.datasets[0].data.push(dom); - timeLineChart.data.datasets[1].data.push(ads); - } + timeLineChart.data.labels.push(date); + timeLineChart.data.datasets[0].data.push(blocked); + timeLineChart.data.datasets[1].data.push(total - blocked); } + } - timeLineChart.options.scales.xAxes[0].display=true; - $("#queries-over-time .overlay").hide(); - timeoutWarning.hide(); - timeLineChart.update(); - }); + timeLineChart.options.scales.xAxes[0].display = true; + $("#queries-over-time .overlay").hide(); + timeoutWarning.hide(); + timeLineChart.update(); + } + ); } -/* global Chart */ $(document).ready(function() { - var ctx = document.getElementById("queryOverTimeChart").getContext("2d"); - timeLineChart = new Chart(ctx, { - type: "line", - data: { - labels: [ 0 ], - datasets: [ - { - label: "Total DNS Queries", - fill: true, - backgroundColor: "rgba(220,220,220,0.5)", - borderColor: "rgba(0, 166, 90,.8)", - pointBorderColor: "rgba(0, 166, 90,.8)", - pointRadius: 1, - pointHoverRadius: 5, - data: [], - pointHitRadius: 5, - cubicInterpolationMode: "monotone" - }, - { - label: "Blocked DNS Queries", - fill: true, - backgroundColor: "rgba(0,192,239,0.5)", - borderColor: "rgba(0,192,239,1)", - pointBorderColor: "rgba(0,192,239,1)", - pointRadius: 1, - pointHoverRadius: 5, - data: [], - pointHitRadius: 5, - cubicInterpolationMode: "monotone" - } - ] + var ctx = document.getElementById("queryOverTimeChart").getContext("2d"); + var blockedColor = "#999"; + var permittedColor = "#00a65a"; + timeLineChart = new Chart(ctx, { + type: "bar", + data: { + labels: [], + datasets: [ + { + label: "Blocked DNS Queries", + fill: true, + backgroundColor: blockedColor, + borderColor: blockedColor, + pointBorderColor: blockedColor, + pointRadius: 1, + pointHoverRadius: 5, + data: [], + pointHitRadius: 5 }, - options: { - tooltips: { - enabled: true, - responsive: true, - mode: "x-axis", - callbacks: { - title: function(tooltipItem, data) { - var label = tooltipItem[0].xLabel; - var time = new Date(label); - var date = time.getFullYear()+"-"+padNumber(time.getMonth()+1)+"-"+padNumber(time.getDate()); - var h = time.getHours(); - var m = time.getMinutes(); - var from = padNumber(h)+":"+padNumber(m)+":00"; - var to = padNumber(h)+":"+padNumber(m+9)+":59"; - return "Queries from "+from+" to "+to+" on "+date; - }, - label: function(tooltipItems, data) { - if(tooltipItems.datasetIndex === 1) - { - var percentage = 0.0; - var total = parseInt(data.datasets[0].data[tooltipItems.index]); - var blocked = parseInt(data.datasets[1].data[tooltipItems.index]); - if(total > 0) - { - percentage = 100.0*blocked/total; - } - return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel + " (" + percentage.toFixed(1) + "%)"; - } - else - { - return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel; - } - } - } - }, - legend: { - display: false - }, - scales: { - xAxes: [{ - type: "time", - display: false, - time: { - displayFormats: { - "minute": "HH:mm", - "hour": "HH:mm", - "day": "HH:mm", - "week": "MMM DD HH:mm", - "month": "MMM DD", - "quarter": "MMM DD", - "year": "MMM DD" - } - } - }], - yAxes: [{ - ticks: { - beginAtZero: true - } - }] - }, - maintainAspectRatio: false + { + label: "Permitted DNS Queries", + fill: true, + backgroundColor: permittedColor, + borderColor: permittedColor, + pointBorderColor: permittedColor, + pointRadius: 1, + pointHoverRadius: 5, + data: [], + pointHitRadius: 5 } - }); + ] + }, + options: { + tooltips: { + enabled: true, + itemSort: function(a, b) { + return b.datasetIndex - a.datasetIndex; + }, + mode: "x-axis", + callbacks: { + title: function(tooltipItem) { + var label = tooltipItem[0].xLabel; + var time = new Date(label); + var from_date = + time.getFullYear() + + "-" + + padNumber(time.getMonth() + 1) + + "-" + + padNumber(time.getDate()); + var from_time = + padNumber(time.getHours()) + + ":" + + padNumber(time.getMinutes()) + + ":" + + padNumber(time.getSeconds()); + time = new Date(time.valueOf() + 1000 * interval); + var until_date = + time.getFullYear() + + "-" + + padNumber(time.getMonth() + 1) + + "-" + + padNumber(time.getDate()); + var until_time = + padNumber(time.getHours()) + + ":" + + padNumber(time.getMinutes()) + + ":" + + padNumber(time.getSeconds()); + + if (from_date === until_date) { + // Abbreviated form for intervals on the same day + // We split title in two lines on small screens + if ($(window).width() < 992) { + until_time += "\n"; + } + + return ("Queries from " + from_time + " to " + until_time + " on " + from_date).split( + "\n " + ); + } + + // Full tooltip for intervals spanning more than one day + // We split title in two lines on small screens + if ($(window).width() < 992) { + from_date += "\n"; + } + + return ( + "Queries from " + + from_date + + " " + + from_time + + " to " + + until_date + + " " + + until_time + ).split("\n "); + }, + label: function(tooltipItems, data) { + if (tooltipItems.datasetIndex === 0) { + var percentage = 0.0; + var permitted = parseInt(data.datasets[1].data[tooltipItems.index]); + var blocked = parseInt(data.datasets[0].data[tooltipItems.index]); + if (permitted + blocked > 0) { + percentage = (100.0 * blocked) / (permitted + blocked); + } + + return ( + data.datasets[tooltipItems.datasetIndex].label + + ": " + + tooltipItems.yLabel + + " (" + + percentage.toFixed(1) + + "%)" + ); + } + + return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel; + } + } + }, + legend: { + display: false + }, + scales: { + xAxes: [ + { + type: "time", + stacked: true, + time: { + unit: "hour", + displayFormats: { + minute: "HH:mm", + hour: "HH:mm", + day: "MMM DD", + week: "MMM DD", + month: "MMM", + quarter: "MMM", + year: "YYYY MMM" + } + } + } + ], + yAxes: [ + { + stacked: true, + ticks: { + beginAtZero: true + } + } + ] + }, + maintainAspectRatio: false + } + }); }); $("#querytime").on("apply.daterangepicker", function(ev, picker) { - $(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat)); - $("#queries-over-time").show(); - updateQueriesOverTime(); + $(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat)); + $("#queries-over-time").show(); + updateQueriesOverTime(); }); -$("#queryOverTimeChart").click(function(evt){ - var activePoints = timeLineChart.getElementAtEvent(evt); - if(activePoints.length > 0) - { - //get the internal index in the chart - var clickedElementindex = activePoints[0]["_index"]; +$("#queryOverTimeChart").click(function(evt) { + var activePoints = timeLineChart.getElementAtEvent(evt); + if (activePoints.length > 0) { + //get the internal index in the chart + var clickedElementindex = activePoints[0]._index; - //get specific label by index - var label = timeLineChart.data.labels[clickedElementindex]; + //get specific label by index + var label = timeLineChart.data.labels[clickedElementindex]; - //get value by index - var from = label/1000; - var until = label/1000 + 600; - window.location.href = "db_queries.php?from="+from+"&until="+until; - } - return false; + //get value by index + var from = label / 1000; + var until = label / 1000 + interval; + window.location.href = "db_queries.php?from=" + from + "&until=" + until; + } + + return false; }); diff --git a/scripts/pi-hole/js/db_lists.js b/scripts/pi-hole/js/db_lists.js index 36228b42..3f055fe8 100644 --- a/scripts/pi-hole/js/db_lists.js +++ b/scripts/pi-hole/js/db_lists.js @@ -1,47 +1,75 @@ /* Pi-hole: A black hole for Internet advertisements -* (c) 2017 Pi-hole, LLC (https://pi-hole.net) -* Network-wide ad blocking via your own hardware. -* -* This file is copyright under the latest version of the EUPL. -* Please see LICENSE file for your rights under this license. */ + * (c) 2017 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ -/*global - moment -*/ +/* global moment:false */ var start__ = moment().subtract(6, "days"); -var from = moment(start__).utc().valueOf()/1000; +var from = + moment(start__) + .utc() + .valueOf() / 1000; var end__ = moment(); -var until = moment(end__).utc().valueOf()/1000; +var until = + moment(end__) + .utc() + .valueOf() / 1000; var timeoutWarning = $("#timeoutWarning"); var listsStillLoading = 0; var dateformat = "MMMM Do YYYY, HH:mm"; -$(function () { - $("#querytime").daterangepicker( +$(function() { + $("#querytime").daterangepicker( { - timePicker: true, timePickerIncrement: 15, - locale: { format: "MMMM Do YYYY, HH:mm" }, - startDate: start__, endDate: end__, + timePicker: true, + timePickerIncrement: 15, + locale: { format: dateformat }, + startDate: start__, + endDate: end__, ranges: { - "Today": [moment().startOf("day"), moment()], - "Yesterday": [moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day")], + Today: [moment().startOf("day"), moment()], + Yesterday: [ + moment() + .subtract(1, "days") + .startOf("day"), + moment() + .subtract(1, "days") + .endOf("day") + ], "Last 7 Days": [moment().subtract(6, "days"), moment()], "Last 30 Days": [moment().subtract(29, "days"), moment()], "This Month": [moment().startOf("month"), moment()], - "Last Month": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")], + "Last Month": [ + moment() + .subtract(1, "month") + .startOf("month"), + moment() + .subtract(1, "month") + .endOf("month") + ], "This Year": [moment().startOf("year"), moment()], "All Time": [moment(0), moment()] }, - "opens": "center", "showDropdowns": true, - "autoUpdateInput": false + opens: "center", + showDropdowns: true, + autoUpdateInput: false }, - function (startt, endt) { - from = moment(startt).utc().valueOf()/1000; - until = moment(endt).utc().valueOf()/1000; - }); + function(startt, endt) { + from = + moment(startt) + .utc() + .valueOf() / 1000; + until = + moment(endt) + .utc() + .valueOf() / 1000; + } + ); }); // Credit: http://stackoverflow.com/questions/1787322/htmlspecialchars-equivalent-in-javascript/4835406#4835406 @@ -50,154 +78,174 @@ function escapeHtml(text) { "&": "&", "<": "<", ">": ">", - "\"": """, - "\'": "'" + '"': """, + "'": "'" }; - return text.replace(/[&<>"']/g, function(m) { return map[m]; }); + return text.replace(/[&<>"']/g, function(m) { + return map[m]; + }); } function updateTopClientsChart() { - $("#client-frequency .overlay").show(); - $.getJSON("api_db.php?topClients&from="+from+"&until="+until, function(data) { + $("#client-frequency .overlay").show(); + $.getJSON("api_db.php?topClients&from=" + from + "&until=" + until, function(data) { + // Clear tables before filling them with data + $("#client-frequency td") + .parent() + .remove(); + var clienttable = $("#client-frequency").find("tbody:last"); + var client, percentage, clientname; + var sum = 0; + for (client in data.top_sources) { + if (Object.prototype.hasOwnProperty.call(data.top_sources, client)) { + sum += data.top_sources[client]; + } + } - // Clear tables before filling them with data - $("#client-frequency td").parent().remove(); - var clienttable = $("#client-frequency").find("tbody:last"); - var client, percentage, clientname, clientip; - var sum = 0; - for (client in data.top_sources) { - if ({}.hasOwnProperty.call(data.top_sources, client)){ - sum += data.top_sources[client]; - } + for (client in data.top_sources) { + if (Object.prototype.hasOwnProperty.call(data.top_sources, client)) { + // Sanitize client + client = escapeHtml(client); + if (escapeHtml(client) !== client) { + // Make a copy with the escaped index if necessary + data.top_sources[escapeHtml(client)] = data.top_sources[client]; } - for (client in data.top_sources) { - - if ({}.hasOwnProperty.call(data.top_sources, client)){ - // Sanitize client - client = escapeHtml(client); - if(escapeHtml(client) !== client) - { - // Make a copy with the escaped index if necessary - data.top_sources[escapeHtml(client)] = data.top_sources[client]; - } - if(client.indexOf("|") > -1) - { - var idx = client.indexOf("|"); - clientname = client.substr(0, idx); - clientip = client.substr(idx+1, client.length-idx); - } - else - { - clientname = client; - clientip = client; - } - - var url = clientname; - percentage = data.top_sources[client] / sum * 100.0; - clienttable.append(" " + url + - " " + data.top_sources[client] + "
      "); - } - + if (client.indexOf("|") > -1) { + var idx = client.indexOf("|"); + clientname = client.substr(0, idx); + } else { + clientname = client; } - $("#client-frequency .overlay").hide(); + percentage = (data.top_sources[client] / sum) * 100.0; + clienttable.append( + " " + + clientname + + " " + + data.top_sources[client] + + '
      ' + ); + } + } - listsStillLoading--; - if(listsStillLoading === 0) - timeoutWarning.hide(); - }); + $("#client-frequency .overlay").hide(); + + listsStillLoading--; + if (listsStillLoading === 0) timeoutWarning.hide(); + }); } function updateTopDomainsChart() { - $("#domain-frequency .overlay").show(); - $.getJSON("api_db.php?topDomains&from="+from+"&until="+until, function(data) { + $("#domain-frequency .overlay").show(); + $.getJSON("api_db.php?topDomains&from=" + from + "&until=" + until, function(data) { + // Clear tables before filling them with data + $("#domain-frequency td") + .parent() + .remove(); + var domaintable = $("#domain-frequency").find("tbody:last"); + var domain, percentage; + var sum = 0; + for (domain in data.top_domains) { + if (Object.prototype.hasOwnProperty.call(data.top_domains, domain)) { + sum += data.top_domains[domain]; + } + } - // Clear tables before filling them with data - $("#domain-frequency td").parent().remove(); - var domaintable = $("#domain-frequency").find("tbody:last"); - var domain, percentage; - var sum = 0; - for (domain in data.top_domains) { - if ({}.hasOwnProperty.call(data.top_domains, domain)){ - sum += data.top_domains[domain]; - } + for (domain in data.top_domains) { + if (Object.prototype.hasOwnProperty.call(data.top_domains, domain)) { + // Sanitize domain + domain = escapeHtml(domain); + if (escapeHtml(domain) !== domain) { + // Make a copy with the escaped index if necessary + data.top_domains[escapeHtml(domain)] = data.top_domains[domain]; } - for (domain in data.top_domains) { + percentage = (data.top_domains[domain] / sum) * 100.0; + domaintable.append( + " " + + domain + + " " + + data.top_domains[domain] + + '
      ' + ); + } + } - if ({}.hasOwnProperty.call(data.top_domains, domain)){ - // Sanitize domain - domain = escapeHtml(domain); - if(escapeHtml(domain) !== domain) - { - // Make a copy with the escaped index if necessary - data.top_domains[escapeHtml(domain)] = data.top_domains[domain]; - } + $("#domain-frequency .overlay").hide(); - percentage = data.top_domains[domain] / sum * 100.0; - domaintable.append(" " + domain + - " " + data.top_domains[domain] + "
      "); - } - - } - - $("#domain-frequency .overlay").hide(); - - listsStillLoading--; - if(listsStillLoading === 0) - timeoutWarning.hide(); - }); + listsStillLoading--; + if (listsStillLoading === 0) timeoutWarning.hide(); + }); } function updateTopAdsChart() { - $("#ad-frequency .overlay").show(); - $.getJSON("api_db.php?topAds&from="+from+"&until="+until, function(data) { + $("#ad-frequency .overlay").show(); + $.getJSON("api_db.php?topAds&from=" + from + "&until=" + until, function(data) { + // Clear tables before filling them with data + $("#ad-frequency td") + .parent() + .remove(); + var adtable = $("#ad-frequency").find("tbody:last"); + var ad, percentage; + var sum = 0; + for (ad in data.top_ads) { + if (Object.prototype.hasOwnProperty.call(data.top_ads, ad)) { + sum += data.top_ads[ad]; + } + } - // Clear tables before filling them with data - $("#ad-frequency td").parent().remove(); - var adtable = $("#ad-frequency").find("tbody:last"); - var ad, percentage; - var sum = 0; - for (ad in data.top_ads) { - if ({}.hasOwnProperty.call(data.top_ads, ad)){ - sum += data.top_ads[ad]; - } + for (ad in data.top_ads) { + if (Object.prototype.hasOwnProperty.call(data.top_ads, ad)) { + // Sanitize ad + ad = escapeHtml(ad); + if (escapeHtml(ad) !== ad) { + // Make a copy with the escaped index if necessary + data.top_ads[escapeHtml(ad)] = data.top_ads[ad]; } - for (ad in data.top_ads) { + percentage = (data.top_ads[ad] / sum) * 100.0; + adtable.append( + " " + + ad + + " " + + data.top_ads[ad] + + '
      ' + ); + } + } - if ({}.hasOwnProperty.call(data.top_ads, ad)){ - // Sanitize ad - ad = escapeHtml(ad); - if(escapeHtml(ad) !== ad) - { - // Make a copy with the escaped index if necessary - data.top_ads[escapeHtml(ad)] = data.top_ads[ad]; - } + $("#ad-frequency .overlay").hide(); - percentage = data.top_ads[ad] / sum * 100.0; - adtable.append(" " + ad + " " + data.top_ads[ad] + "
      "); - } - - } - - $("#ad-frequency .overlay").hide(); - - listsStillLoading--; - if(listsStillLoading === 0) - timeoutWarning.hide(); - }); + listsStillLoading--; + if (listsStillLoading === 0) timeoutWarning.hide(); + }); } $("#querytime").on("apply.daterangepicker", function(ev, picker) { - $(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat)); - timeoutWarning.show(); - listsStillLoading = 3; - updateTopClientsChart(); - updateTopDomainsChart(); - updateTopAdsChart(); + $(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat)); + timeoutWarning.show(); + listsStillLoading = 3; + updateTopClientsChart(); + updateTopDomainsChart(); + updateTopAdsChart(); }); diff --git a/scripts/pi-hole/js/db_queries.js b/scripts/pi-hole/js/db_queries.js index c7a746b3..0952674a 100644 --- a/scripts/pi-hole/js/db_queries.js +++ b/scripts/pi-hole/js/db_queries.js @@ -1,18 +1,22 @@ /* Pi-hole: A black hole for Internet advertisements -* (c) 2017 Pi-hole, LLC (https://pi-hole.net) -* Network-wide ad blocking via your own hardware. -* -* This file is copyright under the latest version of the EUPL. -* Please see LICENSE file for your rights under this license. */ + * (c) 2017 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ -/*global - moment -*/ +/* global moment:false */ var start__ = moment().subtract(6, "days"); -var from = moment(start__).utc().valueOf()/1000; +var from = + moment(start__) + .utc() + .valueOf() / 1000; var end__ = moment(); -var until = moment(end__).utc().valueOf()/1000; +var until = + moment(end__) + .utc() + .valueOf() / 1000; var instantquery = false; var daterange; @@ -22,343 +26,402 @@ var dateformat = "MMMM Do YYYY, HH:mm"; // Do we want to filter queries? var GETDict = {}; -location.search.substr(1).split("&").forEach(function(item) {GETDict[item.split("=")[0]] = item.split("=")[1];}); +window.location.search + .substr(1) + .split("&") + .forEach(function(item) { + GETDict[item.split("=")[0]] = item.split("=")[1]; + }); -if("from" in GETDict && "until" in GETDict) -{ - from = parseInt(GETDict["from"]); - until = parseInt(GETDict["until"]); - start__ = moment(1000*from); - end__ = moment(1000*until); - instantquery = true; +if ("from" in GETDict && "until" in GETDict) { + from = parseInt(GETDict.from); + until = parseInt(GETDict.until); + start__ = moment(1000 * from); + end__ = moment(1000 * until); + instantquery = true; } -$(function () { - daterange = $("#querytime").daterangepicker( +$(function() { + daterange = $("#querytime").daterangepicker( { - timePicker: true, timePickerIncrement: 15, - locale: { format: "MMMM Do YYYY, HH:mm" }, - startDate: start__, endDate: end__, + timePicker: true, + timePickerIncrement: 15, + locale: { format: dateformat }, + startDate: start__, + endDate: end__, ranges: { - "Today": [moment().startOf("day"), moment()], - "Yesterday": [moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day")], + Today: [moment().startOf("day"), moment()], + Yesterday: [ + moment() + .subtract(1, "days") + .startOf("day"), + moment() + .subtract(1, "days") + .endOf("day") + ], "Last 7 Days": [moment().subtract(6, "days"), moment()], "Last 30 Days": [moment().subtract(29, "days"), moment()], "This Month": [moment().startOf("month"), moment()], - "Last Month": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")], + "Last Month": [ + moment() + .subtract(1, "month") + .startOf("month"), + moment() + .subtract(1, "month") + .endOf("month") + ], "This Year": [moment().startOf("year"), moment()], "All Time": [moment(0), moment()] }, - "opens": "center", "showDropdowns": true, - "autoUpdateInput": false + opens: "center", + showDropdowns: true, + autoUpdateInput: false }, - function (startt, endt) { - from = moment(startt).utc().valueOf()/1000; - until = moment(endt).utc().valueOf()/1000; - }); + function(startt, endt) { + from = + moment(startt) + .utc() + .valueOf() / 1000; + until = + moment(endt) + .utc() + .valueOf() / 1000; + } + ); }); var tableApi, statistics; -function escapeRegex(text) { - var map = { - "(": "\\(", - ")": "\\)", - ".": "\\.", - }; - return text.replace(/[().]/g, function(m) { return map[m]; }); +function add(domain, list) { + var token = $("#token").text(); + var alInfo = $("#alInfo"); + var alList = $("#alList"); + var alDomain = $("#alDomain"); + alDomain.html(domain); + var alSuccess = $("#alSuccess"); + var alFailure = $("#alFailure"); + var err = $("#err"); + + if (list === "white") { + alList.html("Whitelist"); + } else { + alList.html("Blacklist"); + } + + alInfo.show(); + alSuccess.hide(); + alFailure.hide(); + $.ajax({ + url: "scripts/pi-hole/php/add.php", + method: "post", + data: { domain: domain, list: list, token: token }, + success: function(response) { + if ( + response.indexOf("not a valid argument") >= 0 || + response.indexOf("is not a valid domain") >= 0 + ) { + alFailure.show(); + err.html(response); + alFailure.delay(4000).fadeOut(2000, function() { + alFailure.hide(); + }); + } else { + alSuccess.show(); + alSuccess.delay(1000).fadeOut(2000, function() { + alSuccess.hide(); + }); + } + + alInfo.delay(1000).fadeOut(2000, function() { + alInfo.hide(); + alList.html(""); + alDomain.html(""); + }); + }, + error: function() { + alFailure.show(); + err.html(""); + alFailure.delay(1000).fadeOut(2000, function() { + alFailure.hide(); + }); + alInfo.delay(1000).fadeOut(2000, function() { + alInfo.hide(); + alList.html(""); + alDomain.html(""); + }); + } + }); } -function add(domain,list) { - var token = $("#token").html(); - var alInfo = $("#alInfo"); - var alList = $("#alList"); - var alDomain = $("#alDomain"); - alDomain.html(domain); - var alSuccess = $("#alSuccess"); - var alFailure = $("#alFailure"); - var err = $("#err"); +function handleAjaxError(xhr, textStatus) { + if (textStatus === "timeout") { + alert("The server took too long to send the data."); + } else if (xhr.responseText.indexOf("Connection refused") >= 0) { + alert("An error occurred while loading the data: Connection refused. Is FTL running?"); + } else { + alert("An unknown error occurred while loading the data.\n" + xhr.responseText); + } - if(list === "white") - { - alList.html("Whitelist"); - } - else - { - alList.html("Blacklist"); - } - - alInfo.show(); - alSuccess.hide(); - alFailure.hide(); - $.ajax({ - url: "scripts/pi-hole/php/add.php", - method: "post", - data: {"domain":domain, "list":list, "token":token}, - success: function(response) { - if (response.indexOf("not a valid argument") >= 0 || response.indexOf("is not a valid domain") >= 0) - { - alFailure.show(); - err.html(response); - alFailure.delay(4000).fadeOut(2000, function() { alFailure.hide(); }); - } - else - { - alSuccess.show(); - alSuccess.delay(1000).fadeOut(2000, function() { alSuccess.hide(); }); - } - alInfo.delay(1000).fadeOut(2000, function() { - alInfo.hide(); - alList.html(""); - alDomain.html(""); - }); - }, - error: function(jqXHR, exception) { - alFailure.show(); - err.html(""); - alFailure.delay(1000).fadeOut(2000, function() { - alFailure.hide(); - }); - alInfo.delay(1000).fadeOut(2000, function() { - alInfo.hide(); - alList.html(""); - alDomain.html(""); - }); - } - }); -} -function handleAjaxError( xhr, textStatus, error ) { - if ( textStatus === "timeout" ) - { - alert( "The server took too long to send the data." ); - } - else if(xhr.responseText.indexOf("Connection refused") >= 0) - { - alert( "An error occurred while loading the data: Connection refused. Is FTL running?" ); - } - else - { - alert( "An unknown error occurred while loading the data.\n"+xhr.responseText ); - } - $("#all-queries_processing").hide(); - tableApi.clear(); - tableApi.draw(); + $("#all-queries_processing").hide(); + tableApi.clear(); + tableApi.draw(); } -function getQueryTypes() -{ - var queryType = []; - if($("#type_gravity").prop("checked")) - { - queryType.push(1); - } - if($("#type_forwarded").prop("checked")) - { - queryType.push(2); - } - if($("#type_cached").prop("checked")) - { - queryType.push(3); - } - if($("#type_regex").prop("checked")) - { - queryType.push(4); - } - if($("#type_blacklist").prop("checked")) - { - queryType.push(5); - } - if($("#type_external").prop("checked")) - { - // Multiple IDs correspond to this status - // We request queries with all of them - queryType.push([6,7,8]); - } - return queryType.join(","); +function getQueryTypes() { + var queryType = []; + if ($("#type_gravity").prop("checked")) { + queryType.push(1); + } + + if ($("#type_forwarded").prop("checked")) { + queryType.push(2); + } + + if ($("#type_cached").prop("checked")) { + queryType.push(3); + } + + if ($("#type_regex").prop("checked")) { + queryType.push(4); + } + + if ($("#type_blacklist").prop("checked")) { + queryType.push(5); + } + + if ($("#type_external").prop("checked")) { + // Multiple IDs correspond to this status + // We request queries with all of them + queryType.push([6, 7, 8]); + } + + if ($("#type_gravity_CNAME").prop("checked")) { + queryType.push(9); + } + + if ($("#type_regex_CNAME").prop("checked")) { + queryType.push(10); + } + + if ($("#type_blacklist_CNAME").prop("checked")) { + queryType.push(11); + } + + return queryType.join(","); } -var reloadCallback = function() -{ - timeoutWarning.hide(); - statistics = [0,0,0,0]; - var data = tableApi.rows().data(); - for (var i = 0; i < data.length; i++) { - statistics[0]++; - if(data[i][4] === 1) - { - statistics[2]++; - } - else if(data[i][4] === 3) - { - statistics[1]++; - } - else if(data[i][4] === 4) - { - statistics[3]++; - } +var reloadCallback = function() { + timeoutWarning.hide(); + statistics = [0, 0, 0, 0]; + var data = tableApi.rows().data(); + for (var i = 0; i < data.length; i++) { + statistics[0]++; + if (data[i][4] === 1) { + statistics[2]++; + } else if (data[i][4] === 3) { + statistics[1]++; + } else if (data[i][4] === 4) { + statistics[3]++; } - $("h3#dns_queries").text(statistics[0].toLocaleString()); - $("h3#ads_blocked_exact").text(statistics[2].toLocaleString()); - $("h3#ads_wildcard_blocked").text(statistics[3].toLocaleString()); + } - var percent = 0.0; - if(statistics[2] + statistics[3] > 0) - { - percent = 100.0*(statistics[2] + statistics[3]) / statistics[0]; - } - $("h3#ads_percentage_today").text(parseFloat(percent).toFixed(1).toLocaleString()+" %"); + $("h3#dns_queries").text(statistics[0].toLocaleString()); + $("h3#ads_blocked_exact").text(statistics[2].toLocaleString()); + $("h3#ads_wildcard_blocked").text(statistics[3].toLocaleString()); + + var percent = 0.0; + if (statistics[2] + statistics[3] > 0) { + percent = (100.0 * (statistics[2] + statistics[3])) / statistics[0]; + } + + $("h3#ads_percentage_today").text( + parseFloat(percent) + .toFixed(1) + .toLocaleString() + " %" + ); }; function refreshTableData() { - timeoutWarning.show(); - var APIstring = "api_db.php?getAllQueries&from="+from+"&until="+until; - // Check if query type filtering is enabled - var queryType = getQueryTypes(); - if(queryType !== "1,2,3,4,5,6") - { - APIstring += "&types="+queryType; - } - statistics = [0,0,0]; - tableApi.ajax.url(APIstring).load(reloadCallback); + timeoutWarning.show(); + var APIstring = "api_db.php?getAllQueries&from=" + from + "&until=" + until; + // Check if query type filtering is enabled + var queryType = getQueryTypes(); + if (queryType !== "1,2,3,4,5,6") { + APIstring += "&types=" + queryType; + } + + statistics = [0, 0, 0]; + tableApi.ajax.url(APIstring).load(reloadCallback); } $(document).ready(function() { - var status; + var APIstring; - var APIstring; - if(instantquery) - { - APIstring = "api_db.php?getAllQueries&from="+from+"&until="+until; - } - else - { - APIstring = "api_db.php?getAllQueries=empty"; - } - // Check if query type filtering is enabled - var queryType = getQueryTypes(); - if(queryType !== 63) // 63 (0b00111111) = all possible query types are selected - { - APIstring += "&types="+queryType; - } + if (instantquery) { + APIstring = "api_db.php?getAllQueries&from=" + from + "&until=" + until; + } else { + APIstring = "api_db.php?getAllQueries=empty"; + } - tableApi = $("#all-queries").DataTable( { - "rowCallback": function( row, data, index ){ - var blocked, fieldtext, buttontext, color; - switch (data[4]) - { - case 1: - blocked = true; - color = "red"; - fieldtext = "Blocked (gravity)"; - buttontext = ""; - break; - case 2: - blocked = false; - color = "green"; - fieldtext = "OK (forwarded)"; - buttontext = ""; - break; - case 3: - blocked = false; - color = "green"; - fieldtext = "OK (cached)"; - buttontext = ""; - break; - case 4: - blocked = true; - color = "red"; - fieldtext = "Blocked (regex/wildcard)"; - buttontext = "" ; - break; - case 5: - blocked = true; - color = "red"; - fieldtext = "Blocked (blacklist)"; - buttontext = "" ; - break; - case 6: - blocked = true; - color = "red"; - fieldtext = "Blocked (external, IP)"; - buttontext = "" ; - break; - case 7: - blocked = true; - color = "red"; - fieldtext = "Blocked (external, NULL)"; - buttontext = "" ; - break; - case 8: - blocked = true; - color = "red"; - fieldtext = "Blocked (external, NXRA)"; - buttontext = "" ; - break; - default: - blocked = false; - color = "black"; - fieldtext = "Unknown"; - buttontext = ""; - } + // Check if query type filtering is enabled + var queryType = getQueryTypes(); + if (queryType !== 63) { + // 63 (0b00111111) = all possible query types are selected + APIstring += "&types=" + queryType; + } - $(row).css("color", color); - $("td:eq(4)", row).html(fieldtext); - $("td:eq(5)", row).html(buttontext); - }, - dom: "<'row'<'col-sm-12'f>>" + - "<'row'<'col-sm-4'l><'col-sm-8'p>>" + - "<'row'<'col-sm-12'<'table-responsive'tr>>>" + - "<'row'<'col-sm-5'i><'col-sm-7'p>>", - "ajax": { - "url": APIstring, - "error": handleAjaxError, - "dataSrc": function(data){ - var dataIndex = 0; - return data.data.map(function(x){ - x[0] = x[0] * 1e6 + (dataIndex++); - return x; - }); - } - }, - "autoWidth" : false, - "processing": true, - "deferRender": true, - "order" : [[0, "desc"]], - "columns": [ - { "width" : "15%", "render": function (data, type, full, meta) { if(type === "display"){return moment.unix(Math.floor(data/1e6)).format("Y-MM-DD []HH:mm:ss z");}else{return data;} }}, - { "width" : "10%" }, - { "width" : "40%" }, - { "width" : "20%" }, - { "width" : "10%" }, - { "width" : "5%" }, - ], - "lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]], - "columnDefs": [ { - "targets": -1, - "data": null, - "defaultContent": "" - } ], - "initComplete": reloadCallback - }); - $("#all-queries tbody").on( "click", "button", function () { - var data = tableApi.row( $(this).parents("tr") ).data(); - if (data[4] === 1 || data[4] === 4 || data[5] === 5) - { - add(data[2],"white"); + tableApi = $("#all-queries").DataTable({ + rowCallback: function(row, data) { + var fieldtext, buttontext, color; + switch (data[4]) { + case 1: + color = "red"; + fieldtext = "Blocked (gravity)"; + buttontext = + ''; + break; + case 2: + color = "green"; + fieldtext = "OK (forwarded)"; + buttontext = + ''; + break; + case 3: + color = "green"; + fieldtext = "OK (cached)"; + buttontext = + ''; + break; + case 4: + color = "red"; + fieldtext = "Blocked (regex blacklist)"; + buttontext = + ''; + break; + case 5: + color = "red"; + fieldtext = "Blocked (exact blacklist)"; + buttontext = + ''; + break; + case 6: + color = "red"; + fieldtext = "Blocked (external, IP)"; + buttontext = ""; + break; + case 7: + color = "red"; + fieldtext = "Blocked (external, NULL)"; + buttontext = ""; + break; + case 8: + color = "red"; + fieldtext = "Blocked (external, NXRA)"; + buttontext = ""; + break; + case 9: + color = "red"; + fieldtext = "Blocked (gravity, CNAME)"; + buttontext = + ''; + break; + case 10: + color = "red"; + fieldtext = "Blocked (regex blacklist, CNAME)"; + buttontext = + ''; + break; + case 11: + color = "red"; + fieldtext = "Blocked (exact blacklist, CNAME)"; + buttontext = + ''; + break; + default: + color = "black"; + fieldtext = "Unknown"; + buttontext = ""; + } + + $(row).css("color", color); + $("td:eq(4)", row).html(fieldtext); + $("td:eq(5)", row).html(buttontext); + + // Substitute domain by "." if empty + var domain = data[2]; + if (domain.length === 0) { + domain = "."; + } + + $("td:eq(2)", row).text(domain); + }, + dom: + "<'row'<'col-sm-12'f>>" + + "<'row'<'col-sm-4'l><'col-sm-8'p>>" + + "<'row'<'col-sm-12'<'table-responsive'tr>>>" + + "<'row'<'col-sm-5'i><'col-sm-7'p>>", + ajax: { + url: APIstring, + error: handleAjaxError, + dataSrc: function(data) { + var dataIndex = 0; + return data.data.map(function(x) { + x[0] = x[0] * 1e6 + dataIndex++; + return x; + }); + } + }, + autoWidth: false, + processing: true, + deferRender: true, + order: [[0, "desc"]], + columns: [ + { + width: "15%", + render: function(data, type) { + if (type === "display") { + return moment + .unix(Math.floor(data / 1e6)) + .format("Y-MM-DD []HH:mm:ss z"); + } + + return data; } - else - { - add(data[2],"black"); - } - } ); - - if(instantquery) - { - daterange.val(start__.format("MMMM Do YYYY, HH:mm") + " - " + end__.format("MMMM Do YYYY, HH:mm")); + }, + { width: "10%" }, + { width: "40%" }, + { width: "20%" }, + { width: "10%" }, + { width: "5%" } + ], + lengthMenu: [ + [10, 25, 50, 100, -1], + [10, 25, 50, 100, "All"] + ], + columnDefs: [ + { + targets: -1, + data: null, + defaultContent: "" + } + ], + initComplete: reloadCallback + }); + $("#all-queries tbody").on("click", "button", function() { + var data = tableApi.row($(this).parents("tr")).data(); + if (data[4] === 1 || data[4] === 4 || data[5] === 5) { + add(data[2], "white"); + } else { + add(data[2], "black"); } -} ); + }); + + if (instantquery) { + daterange.val(start__.format(dateformat) + " - " + end__.format(dateformat)); + } +}); $("#querytime").on("apply.daterangepicker", function(ev, picker) { - $(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat)); - refreshTableData(); + $(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat)); + refreshTableData(); }); diff --git a/scripts/pi-hole/js/debug.js b/scripts/pi-hole/js/debug.js index 0a6b3ab1..fb0fd35b 100644 --- a/scripts/pi-hole/js/debug.js +++ b/scripts/pi-hole/js/debug.js @@ -1,66 +1,77 @@ +/* Pi-hole: A black hole for Internet advertisements + * (c) 2017 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ + +/* global ActiveXObject: false */ + // Credit: http://stackoverflow.com/a/10642418/2087442 -function httpGet(ta,theUrl) -{ - var xmlhttp; - if (window.XMLHttpRequest) - { +function httpGet(ta, theUrl) { + var xmlhttp; + if (window.XMLHttpRequest) { // code for IE7+ - xmlhttp = new XMLHttpRequest(); - } - else - { + xmlhttp = new XMLHttpRequest(); + } else { // code for IE6, IE5 - xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); + xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); + } + + xmlhttp.onreadystatechange = function() { + if (xmlhttp.readyState === 4 && xmlhttp.status === 200) { + ta.show(); + ta.empty(); + ta.append(xmlhttp.responseText); } - xmlhttp.onreadystatechange=function() - { - if (xmlhttp.readyState === 4 && xmlhttp.status === 200) - { - ta.show(); - ta.empty(); - ta.append(xmlhttp.responseText); - } - }; - xmlhttp.open("GET", theUrl, false); - xmlhttp.send(); + }; + + xmlhttp.open("GET", theUrl, false); + xmlhttp.send(); } function eventsource() { - var ta = $("#output"); - var upload = $( "#upload" ); - var checked = ""; - var token = encodeURIComponent($("#token").html()); + var ta = $("#output"); + var upload = $("#upload"); + var checked = ""; + var token = encodeURIComponent($("#token").text()); - if(upload.prop("checked")) - { - checked = "upload"; - } + if (upload.prop("checked")) { + checked = "upload"; + } - // IE does not support EventSource - load whole content at once - if (typeof EventSource !== "function") { - httpGet(ta,"/admin/scripts/pi-hole/php/debug.php?IE&token="+token+"&"+checked); - return; - } + // IE does not support EventSource - load whole content at once + if (typeof EventSource !== "function") { + httpGet(ta, "scripts/pi-hole/php/debug.php?IE&token=" + token + "&" + checked); + return; + } - var host = window.location.host; - var source = new EventSource("/admin/scripts/pi-hole/php/debug.php?&token="+token+"&"+checked); + var source = new EventSource("scripts/pi-hole/php/debug.php?&token=" + token + "&" + checked); - // Reset and show field - ta.empty(); - ta.show(); + // Reset and show field + ta.empty(); + ta.show(); - source.addEventListener("message", function(e) { - ta.append(e.data); - }, false); + source.addEventListener( + "message", + function(e) { + ta.append(e.data); + }, + false + ); - // Will be called when script has finished - source.addEventListener("error", function(e) { - source.close(); - }, false); + // Will be called when script has finished + source.addEventListener( + "error", + function() { + source.close(); + }, + false + ); } -$("#debugBtn").on("click", function(){ - $("#debugBtn").attr("disabled", true); - $("#upload").attr("disabled", true); - eventsource(); +$("#debugBtn").on("click", function() { + $("#debugBtn").attr("disabled", true); + $("#upload").attr("disabled", true); + eventsource(); }); diff --git a/scripts/pi-hole/js/footer.js b/scripts/pi-hole/js/footer.js index 155efa29..7c709625 100644 --- a/scripts/pi-hole/js/footer.js +++ b/scripts/pi-hole/js/footer.js @@ -1,208 +1,198 @@ /* Pi-hole: A black hole for Internet advertisements -* (c) 2017 Pi-hole, LLC (https://pi-hole.net) -* Network-wide ad blocking via your own hardware. -* -* This file is copyright under the latest version of the EUPL. -* Please see LICENSE file for your rights under this license. */ + * (c) 2017 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ + //The following functions allow us to display time until pi-hole is enabled after disabling. //Works between all pages function secondsTimeSpanToHMS(s) { - var h = Math.floor(s/3600); //Get whole hours - s -= h*3600; - var m = Math.floor(s/60); //Get remaining minutes - s -= m*60; - return h+":"+(m < 10 ? "0"+m : m)+":"+(s < 10 ? "0"+s : s); //zero padding on minutes and seconds + var h = Math.floor(s / 3600); //Get whole hours + s -= h * 3600; + var m = Math.floor(s / 60); //Get remaining minutes + s -= m * 60; + return h + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s); //zero padding on minutes and seconds } -function piholeChanged(action) -{ - var status = $("#status"); - var ena = $("#pihole-enable"); - var dis = $("#pihole-disable"); +function piholeChanged(action) { + var status = $("#status"); + var ena = $("#pihole-enable"); + var dis = $("#pihole-disable"); - switch(action) { - case "enabled": - status.html(" Active"); - ena.hide(); - dis.show(); - dis.removeClass("active"); - break; + switch (action) { + case "enabled": + status.html(" Active"); + ena.hide(); + dis.show(); + dis.removeClass("active"); + break; - case "disabled": - status.html(" Offline"); - ena.show(); - dis.hide(); - break; - } + case "disabled": + status.html(" Offline"); + ena.show(); + dis.hide(); + break; + default: + // nothing + } } -function countDown(){ - var ena = $("#enableLabel"); - var enaT = $("#enableTimer"); - var target = new Date(parseInt(enaT.html())); - var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000); +function countDown() { + var ena = $("#enableLabel"); + var enaT = $("#enableTimer"); + var target = new Date(parseInt(enaT.html())); + var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000); - if(seconds > 0){ - setTimeout(countDown,1000); - ena.text("Enable (" + secondsTimeSpanToHMS(seconds) + ")"); - } - else - { - ena.text("Enable"); - piholeChanged("enabled"); - localStorage.removeItem("countDownTarget"); - } + if (seconds > 0) { + setTimeout(countDown, 1000); + ena.text("Enable (" + secondsTimeSpanToHMS(seconds) + ")"); + } else { + ena.text("Enable"); + piholeChanged("enabled"); + localStorage.removeItem("countDownTarget"); + } } -function piholeChange(action, duration) -{ - var token = encodeURIComponent($("#token").html()); - var enaT = $("#enableTimer"); - var btnStatus; +function piholeChange(action, duration) { + var token = encodeURIComponent($("#token").text()); + var enaT = $("#enableTimer"); + var btnStatus; - switch(action) { - case "enable": - btnStatus = $("#flip-status-enable"); - btnStatus.html(" "); - $.getJSON("api.php?enable&token=" + token, function(data) { - if(data.status === "enabled") { - btnStatus.html(""); - piholeChanged("enabled"); - } - }); - break; + switch (action) { + case "enable": + btnStatus = $("#flip-status-enable"); + btnStatus.html(" "); + $.getJSON("api.php?enable&token=" + token, function(data) { + if (data.status === "enabled") { + btnStatus.html(""); + piholeChanged("enabled"); + } + }); + break; - case "disable": - btnStatus = $("#flip-status-disable"); - btnStatus.html(" "); - $.getJSON("api.php?disable=" + duration + "&token=" + token, function(data) { - if(data.status === "disabled") { - btnStatus.html(""); - piholeChanged("disabled"); - if(duration > 0) - { - enaT.html(new Date().getTime() + duration * 1000); - setTimeout(countDown,100); - } - } - }); - break; - } + case "disable": + btnStatus = $("#flip-status-disable"); + btnStatus.html(" "); + $.getJSON("api.php?disable=" + duration + "&token=" + token, function(data) { + if (data.status === "disabled") { + btnStatus.html(""); + piholeChanged("disabled"); + if (duration > 0) { + enaT.html(new Date().getTime() + duration * 1000); + setTimeout(countDown, 100); + } + } + }); + break; + + default: + // nothing + } } -$( document ).ready(function() { - var enaT = $("#enableTimer"); - var target = new Date(parseInt(enaT.html())); - var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000); - if (seconds > 0) - { - setTimeout(countDown,100); - } +$(document).ready(function() { + var enaT = $("#enableTimer"); + var target = new Date(parseInt(enaT.html())); + var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000); + if (seconds > 0) { + setTimeout(countDown, 100); + } }); // Handle Enable/Disable -$("#pihole-enable").on("click", function(e){ - e.preventDefault(); - localStorage.removeItem("countDownTarget"); - piholeChange("enable",""); +$("#pihole-enable").on("click", function(e) { + e.preventDefault(); + localStorage.removeItem("countDownTarget"); + piholeChange("enable", ""); }); -$("#pihole-disable-permanently").on("click", function(e){ - e.preventDefault(); - piholeChange("disable","0"); +$("#pihole-disable-permanently").on("click", function(e) { + e.preventDefault(); + piholeChange("disable", "0"); }); -$("#pihole-disable-10s").on("click", function(e){ - e.preventDefault(); - piholeChange("disable","10"); +$("#pihole-disable-10s").on("click", function(e) { + e.preventDefault(); + piholeChange("disable", "10"); }); -$("#pihole-disable-30s").on("click", function(e){ - e.preventDefault(); - piholeChange("disable","30"); +$("#pihole-disable-30s").on("click", function(e) { + e.preventDefault(); + piholeChange("disable", "30"); }); -$("#pihole-disable-5m").on("click", function(e){ - e.preventDefault(); - piholeChange("disable","300"); +$("#pihole-disable-5m").on("click", function(e) { + e.preventDefault(); + piholeChange("disable", "300"); }); -$("#pihole-disable-custom").on("click", function(e){ - e.preventDefault(); - var custVal = $("#customTimeout").val(); - custVal = $("#btnMins").hasClass("active") ? custVal * 60 : custVal; - piholeChange("disable",custVal); +$("#pihole-disable-custom").on("click", function(e) { + e.preventDefault(); + var custVal = $("#customTimeout").val(); + custVal = $("#btnMins").hasClass("active") ? custVal * 60 : custVal; + piholeChange("disable", custVal); }); // Session timer -var sessionvalidity = parseInt(document.getElementById("sessiontimercounter").textContent); -var start = new Date; +var sessionTimerCounter = document.getElementById("sessiontimercounter"); +var sessionvalidity = parseInt(sessionTimerCounter.textContent); +var start = new Date(); -function updateSessionTimer() -{ - start = new Date; - start.setSeconds(start.getSeconds() + sessionvalidity); +function updateSessionTimer() { + start = new Date(); + start.setSeconds(start.getSeconds() + sessionvalidity); } -if(sessionvalidity > 0) -{ - // setSeconds will correctly handle wrap-around cases - updateSessionTimer(); +if (sessionvalidity > 0) { + // setSeconds will correctly handle wrap-around cases + updateSessionTimer(); - setInterval(function() { - var current = new Date; - var totalseconds = (start - current) / 1000; + setInterval(function() { + var current = new Date(); + var totalseconds = (start - current) / 1000; + var minutes = Math.floor(totalseconds / 60); + if (minutes < 10) { + minutes = "0" + minutes; + } - // var hours = Math.floor(totalseconds / 3600); - // totalseconds = totalseconds % 3600; + var seconds = Math.floor(totalseconds % 60); + if (seconds < 10) { + seconds = "0" + seconds; + } - var minutes = Math.floor(totalseconds / 60); - if(minutes < 10){ minutes = "0" + minutes; } - - var seconds = Math.floor(totalseconds % 60); - if(seconds < 10){ seconds = "0" + seconds; } - - if(totalseconds > 0) - { - document.getElementById("sessiontimercounter").textContent = minutes + ":" + seconds; - } - else - { - document.getElementById("sessiontimercounter").textContent = "-- : --"; - } - - }, 1000); -} -else -{ - document.getElementById("sessiontimer").style.display = "none"; + if (totalseconds > 0) { + sessionTimerCounter.textContent = minutes + ":" + seconds; + } else { + sessionTimerCounter.textContent = "-- : --"; + } + }, 1000); +} else { + document.getElementById("sessiontimer").style.display = "none"; } // Handle Strg + Enter button on Login page $(document).keypress(function(e) { - if((e.keyCode === 10 || e.keyCode === 13) && e.ctrlKey && $("#loginpw").is(":focus")) { - $("#loginform").attr("action", "settings.php"); - $("#loginform").submit(); - } + if ((e.keyCode === 10 || e.keyCode === 13) && e.ctrlKey && $("#loginpw").is(":focus")) { + $("#loginform").attr("action", "settings.php"); + $("#loginform").submit(); + } }); -function testCookies() -{ - if (navigator.cookieEnabled) - { - return true; - } +function testCookies() { + if (navigator.cookieEnabled) { + return true; + } - // set and read cookie - document.cookie = "cookietest=1"; - var ret = document.cookie.indexOf("cookietest=") !== -1; + // set and read cookie + document.cookie = "cookietest=1"; + var ret = document.cookie.indexOf("cookietest=") !== -1; - // delete cookie - document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT"; + // delete cookie + document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT"; - return ret; + return ret; } $(function() { - if(!testCookies() && $("#cookieInfo").length) - { - $("#cookieInfo").show(); - } + if (!testCookies() && $("#cookieInfo").length) { + $("#cookieInfo").show(); + } }); diff --git a/scripts/pi-hole/js/gravity.js b/scripts/pi-hole/js/gravity.js index bf31254b..1512a800 100644 --- a/scripts/pi-hole/js/gravity.js +++ b/scripts/pi-hole/js/gravity.js @@ -1,72 +1,80 @@ /* Pi-hole: A black hole for Internet advertisements -* (c) 2017 Pi-hole, LLC (https://pi-hole.net) -* Network-wide ad blocking via your own hardware. -* -* This file is copyright under the latest version of the EUPL. -* Please see LICENSE file for your rights under this license. */ + * (c) 2017 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ + function eventsource() { - var alInfo = $("#alInfo"); - var alSuccess = $("#alSuccess"); - var ta = $("#output"); + var alInfo = $("#alInfo"); + var alSuccess = $("#alSuccess"); + var ta = $("#output"); - // IE does not support EventSource - exit early - if (typeof EventSource !== "function") { - ta.show(); - ta.html("Updating lists of ad-serving domains is not supported with this browser!"); - return; - } - var source = new EventSource("scripts/pi-hole/php/gravity.sh.php"); - - ta.html(""); + // IE does not support EventSource - exit early + if (typeof EventSource !== "function") { ta.show(); - alInfo.show(); - alSuccess.hide(); + ta.html("Updating lists of ad-serving domains is not supported with this browser!"); + return; + } - source.addEventListener("message", function(e) { - if(e.data.indexOf("Pi-hole blocking is") !== -1) - { - alSuccess.show(); - } + var source = new EventSource("scripts/pi-hole/php/gravity.sh.php"); - // Detect ${OVER} - if(e.data.indexOf("<------") !== -1) - { - ta.text(ta.text().substring(0, ta.text().lastIndexOf("\n")) + "\n"); - var new_string = e.data.replace("<------", ""); - ta.append(new_string); - } - else - { - ta.append(e.data); - } + ta.html(""); + ta.show(); + alInfo.show(); + alSuccess.hide(); - }, false); + source.addEventListener( + "message", + function(e) { + if (e.data.indexOf("Pi-hole blocking is") !== -1) { + alSuccess.show(); + } - // Will be called when script has finished - source.addEventListener("error", function(e) { - alInfo.delay(1000).fadeOut(2000, function() { alInfo.hide(); }); - source.close(); - $("#gravityBtn").removeAttr("disabled"); - }, false); + // Detect ${OVER} + if (e.data.indexOf("<------") !== -1) { + ta.text(ta.text().substring(0, ta.text().lastIndexOf("\n")) + "\n"); + var new_string = e.data.replace("<------", ""); + ta.append(new_string); + } else { + ta.append(e.data); + } + }, + false + ); + + // Will be called when script has finished + source.addEventListener( + "error", + function() { + alInfo.delay(1000).fadeOut(2000, function() { + alInfo.hide(); + }); + source.close(); + $("#gravityBtn").removeAttr("disabled"); + }, + false + ); } -$("#gravityBtn").on("click", function(){ - $("#gravityBtn").attr("disabled", true); - eventsource(); +$("#gravityBtn").on("click", function() { + $("#gravityBtn").attr("disabled", true); + eventsource(); }); // Handle hiding of alerts -$(function(){ - $("[data-hide]").on("click", function(){ - $(this).closest("." + $(this).attr("data-hide")).hide(); - }); +$(function() { + $("[data-hide]").on("click", function() { + $(this) + .closest("." + $(this).attr("data-hide")) + .hide(); + }); - // Do we want to start updating immediately? - // gravity.php?go - var searchString = window.location.search.substring(1); - if(searchString.indexOf("go") !== -1) - { - $("#gravityBtn").attr("disabled", true); - eventsource(); - } + // Do we want to start updating immediately? + // gravity.php?go + var searchString = window.location.search.substring(1); + if (searchString.indexOf("go") !== -1) { + $("#gravityBtn").attr("disabled", true); + eventsource(); + } }); diff --git a/scripts/pi-hole/js/groups-adlists.js b/scripts/pi-hole/js/groups-adlists.js new file mode 100644 index 00000000..a961db98 --- /dev/null +++ b/scripts/pi-hole/js/groups-adlists.js @@ -0,0 +1,382 @@ +/* Pi-hole: A black hole for Internet advertisements + * (c) 2017 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ + +/* global utils:false */ + +var table; +var groups = []; +var token = $("#token").html(); + +function get_groups() { + $.post( + "scripts/pi-hole/php/groups.php", + { action: "get_groups", token: token }, + function(data) { + groups = data.data; + initTable(); + }, + "json" + ); +} + +$(document).ready(function() { + $("#btnAdd").on("click", addAdlist); + + utils.bsSelect_defaults(); + get_groups(); +}); + +function initTable() { + table = $("#adlistsTable").DataTable({ + ajax: { + url: "scripts/pi-hole/php/groups.php", + data: { action: "get_adlists", token: token }, + type: "POST" + }, + order: [[0, "asc"]], + columns: [ + { data: "id", visible: false }, + { data: "address" }, + { data: "enabled", searchable: false }, + { data: "comment" }, + { data: "groups", searchable: false }, + { data: null, width: "80px", orderable: false } + ], + drawCallback: function() { + $('button[id^="deleteAdlist_"]').on("click", deleteAdlist); + // Remove visible dropdown to prevent orphaning + $("body > .bootstrap-select.dropdown").remove(); + }, + rowCallback: function(row, data) { + $(row).attr("data-id", data.id); + var tooltip = + "Added: " + + utils.datetime(data.date_added) + + "\nLast modified: " + + utils.datetime(data.date_modified) + + "\nDatabase ID: " + + data.id; + $("td:eq(0)", row).html( + '' + + data.address + + "" + ); + + var disabled = data.enabled === 0; + $("td:eq(1)", row).html( + '" + ); + var statusEl = $("#status_" + data.id, row); + statusEl.bootstrapToggle({ + on: "Enabled", + off: "Disabled", + size: "small", + onstyle: "success", + width: "80px" + }); + statusEl.on("change", editAdlist); + + $("td:eq(2)", row).html(''); + var commentEl = $("#comment_" + data.id, row); + commentEl.val(data.comment); + commentEl.on("change", editAdlist); + + $("td:eq(3)", row).empty(); + $("td:eq(3)", row).append( + '' + ); + var selectEl = $("#multiselect_" + data.id, row); + // Add all known groups + for (var i = 0; i < groups.length; i++) { + var data_sub = ""; + if (!groups[i].enabled) { + data_sub = 'data-subtext="(disabled)"'; + } + + selectEl.append( + $("" + + '"; + } + + var blacklist_options = ""; + if (showtype === "all" || showtype === "black") { + blacklist_options = + '" + + '"; + } + + $("td:eq(1)", row).html( + '" + ); + var typeEl = $("#type_" + data.id, row); + typeEl.on("change", editDomain); + + var disabled = data.enabled === 0; + $("td:eq(2)", row).html( + '" + ); + var statusEl = $("#status_" + data.id, row); + statusEl.bootstrapToggle({ + on: "Enabled", + off: "Disabled", + size: "small", + onstyle: "success", + width: "80px" + }); + statusEl.on("change", editDomain); + + $("td:eq(3)", row).html(''); + var commentEl = $("#comment_" + data.id, row); + commentEl.val(data.comment); + commentEl.on("change", editDomain); + + // Show group assignment field only if in full domain management mode + if (table.column(5).visible()) { + $("td:eq(4)", row).empty(); + $("td:eq(4)", row).append( + '' + ); + var selectEl = $("#multiselect_" + data.id, row); + // Add all known groups + for (var i = 0; i < groups.length; i++) { + var data_sub = ""; + if (!groups[i].enabled) { + data_sub = 'data-subtext="(disabled)"'; + } + + selectEl.append( + $("
      @@ -52,17 +52,17 @@ Pi-hole Version (Update available!) + if($core_update){ ?> (Update available!) Web Interface Version (Update available!) + if($web_update){ ?> (Update available!) FTL Version (Update available!) + if($FTL_update){ ?> (Update available!)
      -
      Donate if you found this useful.
      +
      Donate if you found this useful.
      diff --git a/scripts/pi-hole/php/func.php b/scripts/pi-hole/php/func.php index 7c1d3d65..269fce7f 100644 --- a/scripts/pi-hole/php/func.php +++ b/scripts/pi-hole/php/func.php @@ -13,6 +13,13 @@ function is_valid_domain_name($domain_name) preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)); // Length of each label } +function get_ip_type($ip) +{ + return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? 4 : + (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? 6 : + 0); +} + function checkfile($filename) { if(is_readable($filename)) { @@ -45,21 +52,4 @@ if(!function_exists('hash_equals')) { } } -function add_regex($regex, $mode=FILE_APPEND, $append="\n") -{ - global $regexfile; - if(file_put_contents($regexfile, $regex.$append, $mode) === FALSE) - { - $err = error_get_last()["message"]; - echo "Unable to add regex \"".htmlspecialchars($regex)."\" to ${regexfile}
      Error message: $err"; - } - else - { - // Send SIGHUP to pihole-FTL using a frontend command - // to force reloading of the regex domains - // This will also wipe the resolver's cache - echo exec("sudo pihole restartdns reload"); - } -} - ?> diff --git a/scripts/pi-hole/php/get.php b/scripts/pi-hole/php/get.php deleted file mode 100644 index 156622c7..00000000 --- a/scripts/pi-hole/php/get.php +++ /dev/null @@ -1,67 +0,0 @@ -= 0; $i--) { - if(strlen($list[$i]) < 1 || $list[$i][0] === '#') - unset($list[$i]); - } - - // Re-index list after possible unset() activity - $newlist = array_values($list); - - return $newlist; - -} - -function filterArray(&$inArray) { - $outArray = array(); - foreach ($inArray as $key=>$value) { - if (is_array($value)) { - $outArray[htmlspecialchars($key)] = filterArray($value); - } else { - $outArray[htmlspecialchars($key)] = htmlspecialchars($value); - } - } - return $outArray; -} - -// Protect against XSS attacks -$list = filterArray($list); -echo json_encode(array_values($list)); diff --git a/scripts/pi-hole/php/gravity.php b/scripts/pi-hole/php/gravity.php index cb3c3404..fbd729e3 100644 --- a/scripts/pi-hole/php/gravity.php +++ b/scripts/pi-hole/php/gravity.php @@ -1,51 +1,61 @@ - | April 23rd, 2018: - Checks when the gravity list was last updated, if it exists at all. - Returns the info in human-readable format for use on the dashboard, - or raw for use by the API. - */ - $gravitylist = "/etc/pihole/gravity.list"; - if (file_exists($gravitylist)){ - $date_file_created_unix = filemtime($gravitylist); - $date_file_created = date_create("@".$date_file_created_unix); - $date_now = date_create("now"); - $gravitydiff = date_diff($date_file_created,$date_now); - if($raw){ - $output = array( - "file_exists"=> true, - "absolute" => $date_file_created_unix, - "relative" => array( - "days" => $gravitydiff->format("%a"), - "hours" => $gravitydiff->format("%H"), - "minutes" => $gravitydiff->format("%I"), - ) - ); - }else{ - if($gravitydiff->d > 1){ - $output = $gravitydiff->format("Blocking list updated %a days, %H:%I ago"); - }elseif($gravitydiff->d == 1){ - $output = $gravitydiff->format("Blocking list updated one day, %H:%I ago"); - }else{ - $output = $gravitydiff->format("Blocking list updated %H:%I ago"); - } - } - }else{ - if($raw){ - $output = array("file_exists"=>false); - }else{ - $output = "Blocking list not found"; - } - } - return $output; -} - -?> \ No newline at end of file +querySingle("SELECT value FROM info WHERE property = 'updated';"); + if($date_file_created_unix === false) + { + if($raw) + { + // Array output + return array("file_exists" => false); + } + else + { + // String output + return "Gravity database not available"; + } + } + // Now that we know that $date_file_created_unix is a valid response, we can convert it to an integer + $date_file_created_unix = intval($date_file_created_unix); + $date_file_created = date_create("@".$date_file_created_unix); + $date_now = date_create("now"); + $gravitydiff = date_diff($date_file_created,$date_now); + if($raw) + { + // Array output + return array( + "file_exists"=> true, + "absolute" => $date_file_created_unix, + "relative" => array( + "days" => intval($gravitydiff->format("%a")), + "hours" => intval($gravitydiff->format("%H")), + "minutes" => intval($gravitydiff->format("%I")), + ) + ); + } + + if($gravitydiff->d > 1) + { + // String output (more than one day ago) + return $gravitydiff->format("Blocking list updated %a days, %H:%I (hh:mm) ago"); + } + elseif($gravitydiff->d == 1) + { + // String output (one day ago) + return $gravitydiff->format("Blocking list updated one day, %H:%I (hh:mm) ago"); + } + + // String output (less than one day ago) + return $gravitydiff->format("Blocking list updated %H:%I (hh:mm) ago"); +} +?> diff --git a/scripts/pi-hole/php/groups.php b/scripts/pi-hole/php/groups.php new file mode 100644 index 00000000..5e4e4bd3 --- /dev/null +++ b/scripts/pi-hole/php/groups.php @@ -0,0 +1,812 @@ + true, 'message' => $message)); +} + +function JSON_error($message = null) +{ + header('Content-type: application/json'); + $response = array('success' => false, 'message' => $message); + if (isset($_POST['action'])) { + array_push($response, array('action' => $_POST['action'])); + } + echo json_encode($response); +} + +if ($_POST['action'] == 'get_groups') { + // List all available groups + try { + $query = $db->query('SELECT * FROM "group";'); + $data = array(); + while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { + array_push($data, $res); + } + echo json_encode(array('data' => $data)); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'add_group') { + // Add new group + try { + $names = explode(' ', trim($_POST['name'])); + $total = count($names); + $added = 0; + $stmt = $db->prepare('INSERT INTO "group" (name,description) VALUES (:name,:desc)'); + if (!$stmt) { + throw new Exception('While preparing statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':desc', $_POST['desc'], SQLITE3_TEXT)) { + throw new Exception('While binding desc: ' . $db->lastErrorMsg()); + } + + foreach ($names as $name) { + if (!$stmt->bindValue(':name', $name, SQLITE3_TEXT)) { + throw new Exception('While binding name: ' . $db->lastErrorMsg() . '
      '. + 'Added ' . $added . " out of ". $total . " groups"); + } + + if (!$stmt->execute()) { + throw new Exception('While executing: ' . $db->lastErrorMsg() . '
      '. + 'Added ' . $added . " out of ". $total . " groups"); + } + $added++; + } + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'edit_group') { + // Edit group identified by ID + try { + $stmt = $db->prepare('UPDATE "group" SET enabled=:enabled, name=:name, description=:desc WHERE id = :id'); + if (!$stmt) { + throw new Exception('While preparing statement: ' . $db->lastErrorMsg()); + } + + $status = ((int) $_POST['status']) !== 0 ? 1 : 0; + if (!$stmt->bindValue(':enabled', $status, SQLITE3_INTEGER)) { + throw new Exception('While binding enabled: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':name', $_POST['name'], SQLITE3_TEXT)) { + throw new Exception('While binding name: ' . $db->lastErrorMsg()); + } + + $desc = $_POST['desc']; + if (strlen($desc) == 0) { + // Store NULL in database for empty descriptions + $desc = null; + } + if (!$stmt->bindValue(':desc', $desc, SQLITE3_TEXT)) { + throw new Exception('While binding desc: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing: ' . $db->lastErrorMsg()); + } + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'delete_group') { + // Delete group identified by ID + try { + $table_name = ['domainlist_by_group', 'client_by_group', 'adlist_by_group', 'group']; + $table_keys = ['group_id', 'group_id', 'group_id', 'id']; + for ($i = 0; $i < count($table_name); $i++) { + $table = $table_name[$i]; + $key = $table_keys[$i]; + + $stmt = $db->prepare("DELETE FROM \"$table\" WHERE $key = :id;"); + if (!$stmt) { + throw new Exception("While preparing DELETE FROM $table statement: " . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception("While binding id to DELETE FROM $table statement: " . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception("While executing DELETE FROM $table statement: " . $db->lastErrorMsg()); + } + + if (!$stmt->reset()) { + throw new Exception("While resetting DELETE FROM $table statement: " . $db->lastErrorMsg()); + } + } + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'get_clients') { + // List all available groups + try { + $QUERYDB = getQueriesDBFilename(); + $FTLdb = SQLite3_connect($QUERYDB); + + $query = $db->query('SELECT * FROM client;'); + if (!$query) { + throw new Exception('Error while querying gravity\'s client table: ' . $db->lastErrorMsg()); + } + + $data = array(); + while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { + $group_query = $db->query('SELECT group_id FROM client_by_group WHERE client_id = ' . $res['id'] . ';'); + if (!$group_query) { + throw new Exception('Error while querying gravity\'s client_by_group table: ' . $db->lastErrorMsg()); + } + + $stmt = $FTLdb->prepare('SELECT name FROM network WHERE id = (SELECT network_id FROM network_addresses WHERE ip = :ip);'); + if (!$stmt) { + throw new Exception('Error while preparing network table statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':ip', $res['ip'], SQLITE3_TEXT)) { + throw new Exception('While binding to network table statement: ' . $db->lastErrorMsg()); + } + + $result = $stmt->execute(); + if (!$result) { + throw new Exception('While executing network table statement: ' . $db->lastErrorMsg()); + } + + // There will always be a result. Unknown host names are NULL + $name_result = $result->fetchArray(SQLITE3_ASSOC); + $res['name'] = $name_result['name']; + + $groups = array(); + while ($gres = $group_query->fetchArray(SQLITE3_ASSOC)) { + array_push($groups, $gres['group_id']); + } + $res['groups'] = $groups; + array_push($data, $res); + } + + echo json_encode(array('data' => $data)); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'get_unconfigured_clients') { + // List all available clients WITHOUT already configured clients + try { + $QUERYDB = getQueriesDBFilename(); + $FTLdb = SQLite3_connect($QUERYDB); + + $query = $FTLdb->query('SELECT DISTINCT ip,network.name FROM network_addresses AS name LEFT JOIN network ON network.id = network_id ORDER BY ip ASC;'); + if (!$query) { + throw new Exception('Error while querying FTL\'s database: ' . $db->lastErrorMsg()); + } + + // Loop over results + $ips = array(); + while ($res = $query->fetchArray(SQLITE3_ASSOC)) { + $ips[$res['ip']] = $res['name'] !== null ? $res['name'] : ''; + } + $FTLdb->close(); + + $query = $db->query('SELECT ip FROM client;'); + if (!$query) { + throw new Exception('Error while querying gravity\'s database: ' . $db->lastErrorMsg()); + } + + // Loop over results, remove already configured clients + while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { + if (isset($ips[$res['ip']])) { + unset($ips[$res['ip']]); + } + } + + echo json_encode($ips); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'add_client') { + // Add new client + try { + $ips = explode(' ', trim($_POST['ip'])); + $total = count($ips); + $added = 0; + $stmt = $db->prepare('INSERT INTO client (ip,comment) VALUES (:ip,:comment)'); + if (!$stmt) { + throw new Exception('While preparing statement: ' . $db->lastErrorMsg()); + } + + foreach ($ips as $ip) { + if (!$stmt->bindValue(':ip', $ip, SQLITE3_TEXT)) { + throw new Exception('While binding ip: ' . $db->lastErrorMsg()); + } + + $comment = $_POST['comment']; + if (strlen($comment) == 0) { + // Store NULL in database for empty comments + $comment = null; + } + if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { + throw new Exception('While binding comment: ' . $db->lastErrorMsg() . '
      '. + 'Added ' . $added . " out of ". $total . " clients"); + } + + if (!$stmt->execute()) { + throw new Exception('While executing: ' . $db->lastErrorMsg() . '
      '. + 'Added ' . $added . " out of ". $total . " clients"); + } + $added++; + } + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'edit_client') { + // Edit client identified by ID + try { + $stmt = $db->prepare('UPDATE client SET comment=:comment WHERE id = :id'); + if (!$stmt) { + throw new Exception('While preparing statement: ' . $db->lastErrorMsg()); + } + + $comment = $_POST['comment']; + if (strlen($comment) == 0) { + // Store NULL in database for empty comments + $comment = null; + } + if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { + throw new Exception('While binding comment: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing: ' . $db->lastErrorMsg()); + } + + $stmt = $db->prepare('DELETE FROM client_by_group WHERE client_id = :id'); + if (!$stmt) { + throw new Exception('While preparing DELETE statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing DELETE statement: ' . $db->lastErrorMsg()); + } + + $db->query('BEGIN TRANSACTION;'); + foreach ($_POST['groups'] as $gid) { + $stmt = $db->prepare('INSERT INTO client_by_group (client_id,group_id) VALUES(:id,:gid);'); + if (!$stmt) { + throw new Exception('While preparing INSERT INTO statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) { + throw new Exception('While binding gid: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing INSERT INTO statement: ' . $db->lastErrorMsg()); + } + } + $db->query('COMMIT;'); + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'delete_client') { + // Delete client identified by ID + try { + $stmt = $db->prepare('DELETE FROM client_by_group WHERE client_id=:id'); + if (!$stmt) { + throw new Exception('While preparing client_by_group statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id to client_by_group statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing client_by_group statement: ' . $db->lastErrorMsg()); + } + + $stmt = $db->prepare('DELETE FROM client WHERE id=:id'); + if (!$stmt) { + throw new Exception('While preparing client statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id to client statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing client statement: ' . $db->lastErrorMsg()); + } + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'get_domains') { + // List all available groups + try { + $limit = ""; + if (isset($_POST["showtype"]) && $_POST["showtype"] === "white"){ + $limit = " WHERE type = 0 OR type = 2"; + } elseif (isset($_POST["showtype"]) && $_POST["showtype"] === "black"){ + $limit = " WHERE type = 1 OR type = 3"; + } + $query = $db->query('SELECT * FROM domainlist'.$limit); + if (!$query) { + throw new Exception('Error while querying gravity\'s domainlist table: ' . $db->lastErrorMsg()); + } + + $data = array(); + while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { + $group_query = $db->query('SELECT group_id FROM domainlist_by_group WHERE domainlist_id = ' . $res['id'] . ';'); + if (!$group_query) { + throw new Exception('Error while querying gravity\'s domainlist_by_group table: ' . $db->lastErrorMsg()); + } + + $groups = array(); + while ($gres = $group_query->fetchArray(SQLITE3_ASSOC)) { + array_push($groups, $gres['group_id']); + } + $res['groups'] = $groups; + if (extension_loaded("intl") && + ($res['type'] === ListType::whitelist || + $res['type'] === ListType::blacklist) ) { + + // Try to convert possible IDNA domain to Unicode, we try the UTS #46 standard first + // as this is the new default, see https://sourceforge.net/p/icu/mailman/message/32980778/ + // We know that this fails for some Google domains violating the standard + // see https://github.com/pi-hole/AdminLTE/issues/1223 + $utf8_domain = false; + if (defined("INTL_IDNA_VARIANT_UTS46")) { + // We have to use the option IDNA_NONTRANSITIONAL_TO_ASCII here + // to ensure sparkasse-gießen.de is not converted into + // sparkass-giessen.de but into xn--sparkasse-gieen-2ib.de + // as mandated by the UTS #46 standard + $utf8_domain = idn_to_utf8($res['domain'], IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); + } + + // If conversion failed, try with the (deprecated!) IDNA 2003 variant + // We have to check for its existance as support of this variant is + // scheduled for removal with PHP 8.0 + // see https://wiki.php.net/rfc/deprecate-and-remove-intl_idna_variant_2003 + if ($utf8_domain === false && defined("INTL_IDNA_VARIANT_2003")) { + $utf8_domain = idn_to_utf8($res['domain'], IDNA_DEFAULT, INTL_IDNA_VARIANT_2003); + } + + // Convert domain name to international form + // if applicable and extension is available + if ($utf8_domain !== false && $res['domain'] !== $utf8_domain) { + $res['domain'] = $utf8_domain.' ('.$res['domain'].')'; + } + } + array_push($data, $res); + } + + + echo json_encode(array('data' => $data)); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'add_domain') { + // Add new domain + try { + $domains = explode(' ', trim($_POST['domain'])); + $total = count($domains); + $added = 0; + $stmt = $db->prepare('INSERT INTO domainlist (domain,type,comment) VALUES (:domain,:type,:comment)'); + if (!$stmt) { + throw new Exception('While preparing statement: ' . $db->lastErrorMsg()); + } + + $type = intval($_POST['type']); + + if (!$stmt->bindValue(':type', $type, SQLITE3_TEXT)) { + throw new Exception('While binding type: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':comment', $_POST['comment'], SQLITE3_TEXT)) { + throw new Exception('While binding comment: ' . $db->lastErrorMsg()); + } + + foreach ($domains as $domain) { + $input = $domain; + // Convert domain name to IDNA ASCII form for international domains + if (extension_loaded("intl")) { + // Be prepared that this may fail and see our comments above + // (search for "idn_to_utf8) + $idn_domain = false; + if (defined("INTL_IDNA_VARIANT_UTS46")) { + $idn_domain = idn_to_ascii($domain, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); + } + if ($idn_domain === false && defined("INTL_IDNA_VARIANT_2003")) { + $idn_domain = idn_to_ascii($domain, IDNA_DEFAULT, INTL_IDNA_VARIANT_2003); + } + if($idn_domain !== false) { + $domain = $idn_domain; + } + } + + if(strlen($_POST['type']) === 2 && $_POST['type'][1] === 'W') + { + // Apply wildcard-style formatting + $domain = "(\\.|^)".str_replace(".","\\.",$domain)."$"; + } + + if($type === ListType::whitelist || $type === ListType::blacklist) + { + // If adding to the exact lists, we convert the domain lower case and check whether it is valid + $domain = strtolower($domain); + if(filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) === false) + { + // This is the case when idn_to_ascii() modified the string + if($input !== $domain && strlen($domain) > 0) + $errormsg = 'Domain ' . htmlentities($input) . ' (converted to "' . htmlentities(utf8_encode($domain)) . '") is not a valid domain.'; + elseif($input !== $domain) + $errormsg = 'Domain ' . htmlentities($input) . ' is not a valid domain.'; + else + $errormsg = 'Domain ' . htmlentities(utf8_encode($domain)) . ' is not a valid domain.'; + throw new Exception($errormsg . '
      Added ' . $added . " out of ". $total . " domains"); + } + } + + if (!$stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) { + throw new Exception('While binding domain: ' . $db->lastErrorMsg() . '
      '. + 'Added ' . $added . " out of ". $total . " domains"); + } + + if (!$stmt->execute()) { + throw new Exception('While executing: ' . $db->lastErrorMsg() . '
      '. + 'Added ' . $added . " out of ". $total . " domains"); + } + $added++; + } + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'edit_domain') { + // Edit domain identified by ID + try { + $stmt = $db->prepare('UPDATE domainlist SET enabled=:enabled, comment=:comment, type=:type WHERE id = :id'); + if (!$stmt) { + throw new Exception('While preparing statement: ' . $db->lastErrorMsg()); + } + + $status = intval($_POST['status']); + if ($status !== 0) { + $status = 1; + } + + if (!$stmt->bindValue(':enabled', $status, SQLITE3_INTEGER)) { + throw new Exception('While binding enabled: ' . $db->lastErrorMsg()); + } + + $comment = $_POST['comment']; + if (strlen($comment) == 0) { + // Store NULL in database for empty comments + $comment = null; + } + if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { + throw new Exception('While binding comment: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':type', intval($_POST['type']), SQLITE3_INTEGER)) { + throw new Exception('While binding type: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing: ' . $db->lastErrorMsg()); + } + + if (isset($_POST['groups'])) { + $stmt = $db->prepare('DELETE FROM domainlist_by_group WHERE domainlist_id = :id'); + if (!$stmt) { + throw new Exception('While preparing DELETE statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing DELETE statement: ' . $db->lastErrorMsg()); + } + + $db->query('BEGIN TRANSACTION;'); + foreach ($_POST['groups'] as $gid) { + $stmt = $db->prepare('INSERT INTO domainlist_by_group (domainlist_id,group_id) VALUES(:id,:gid);'); + if (!$stmt) { + throw new Exception('While preparing INSERT INTO statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) { + throw new Exception('While binding gid: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing INSERT INTO statement: ' . $db->lastErrorMsg()); + } + } + $db->query('COMMIT;'); + } + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'delete_domain') { + // Delete domain identified by ID + try { + $stmt = $db->prepare('DELETE FROM domainlist_by_group WHERE domainlist_id=:id'); + if (!$stmt) { + throw new Exception('While preparing domainlist_by_group statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id to domainlist_by_group statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing domainlist_by_group statement: ' . $db->lastErrorMsg()); + } + + $stmt = $db->prepare('DELETE FROM domainlist WHERE id=:id'); + if (!$stmt) { + throw new Exception('While preparing domainlist statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id to domainlist statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing domainlist statement: ' . $db->lastErrorMsg()); + } + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'get_adlists') { + // List all available groups + try { + $query = $db->query('SELECT * FROM adlist;'); + if (!$query) { + throw new Exception('Error while querying gravity\'s adlist table: ' . $db->lastErrorMsg()); + } + + $data = array(); + while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { + $group_query = $db->query('SELECT group_id FROM adlist_by_group WHERE adlist_id = ' . $res['id'] . ';'); + if (!$group_query) { + throw new Exception('Error while querying gravity\'s adlist_by_group table: ' . $db->lastErrorMsg()); + } + + $groups = array(); + while ($gres = $group_query->fetchArray(SQLITE3_ASSOC)) { + array_push($groups, $gres['group_id']); + } + $res['groups'] = $groups; + array_push($data, $res); + } + + + echo json_encode(array('data' => $data)); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'add_adlist') { + // Add new adlist + try { + $addresses = explode(' ', trim($_POST['address'])); + $total = count($addresses); + $added = 0; + + $stmt = $db->prepare('INSERT INTO adlist (address,comment) VALUES (:address,:comment)'); + if (!$stmt) { + throw new Exception('While preparing statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':comment', $_POST['comment'], SQLITE3_TEXT)) { + throw new Exception('While binding comment: ' . $db->lastErrorMsg()); + } + + foreach ($addresses as $address) { + if(preg_match("/[^a-zA-Z0-9:\/?&%=~._()-]/", $address) !== 0) { + throw new Exception('Invalid adlist URL ' . htmlentities($address) . '
      '. + 'Added ' . $added . " out of ". $total . " adlists"); + } + + if (!$stmt->bindValue(':address', $address, SQLITE3_TEXT)) { + throw new Exception('While binding address: ' . $db->lastErrorMsg() . '
      '. + 'Added ' . $added . " out of ". $total . " adlists"); + } + + if (!$stmt->execute()) { + throw new Exception('While executing: ' . $db->lastErrorMsg() . '
      '. + 'Added ' . $added . " out of ". $total . " adlists"); + } + $added++; + } + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'edit_adlist') { + // Edit adlist identified by ID + try { + $stmt = $db->prepare('UPDATE adlist SET enabled=:enabled, comment=:comment WHERE id = :id'); + if (!$stmt) { + throw new Exception('While preparing statement: ' . $db->lastErrorMsg()); + } + + $status = intval($_POST['status']); + if ($status !== 0) { + $status = 1; + } + + if (!$stmt->bindValue(':enabled', $status, SQLITE3_INTEGER)) { + throw new Exception('While binding enabled: ' . $db->lastErrorMsg()); + } + + $comment = $_POST['comment']; + if (strlen($comment) == 0) { + // Store NULL in database for empty comments + $comment = null; + } + if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { + throw new Exception('While binding comment: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing: ' . $db->lastErrorMsg()); + } + + $stmt = $db->prepare('DELETE FROM adlist_by_group WHERE adlist_id = :id'); + if (!$stmt) { + throw new Exception('While preparing DELETE statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing DELETE statement: ' . $db->lastErrorMsg()); + } + + $db->query('BEGIN TRANSACTION;'); + foreach ($_POST['groups'] as $gid) { + $stmt = $db->prepare('INSERT INTO adlist_by_group (adlist_id,group_id) VALUES(:id,:gid);'); + if (!$stmt) { + throw new Exception('While preparing INSERT INTO statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) { + throw new Exception('While binding gid: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing INSERT INTO statement: ' . $db->lastErrorMsg()); + } + } + $db->query('COMMIT;'); + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} elseif ($_POST['action'] == 'delete_adlist') { + // Delete adlist identified by ID + try { + $stmt = $db->prepare('DELETE FROM adlist_by_group WHERE adlist_id=:id'); + if (!$stmt) { + throw new Exception('While preparing adlist_by_group statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id to adlist_by_group statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing adlist_by_group statement: ' . $db->lastErrorMsg()); + } + + $stmt = $db->prepare('DELETE FROM adlist WHERE id=:id'); + if (!$stmt) { + throw new Exception('While preparing adlist statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { + throw new Exception('While binding id to adlist statement: ' . $db->lastErrorMsg()); + } + + if (!$stmt->execute()) { + throw new Exception('While executing adlist statement: ' . $db->lastErrorMsg()); + } + + $reload = true; + JSON_success(); + } catch (\Exception $ex) { + JSON_error($ex->getMessage()); + } +} else { + log_and_die('Requested action not supported!'); +} +// Reload lists in pihole-FTL after having added something +if ($reload) { + echo shell_exec('sudo pihole restartdns reload-lists'); +} diff --git a/scripts/pi-hole/php/header.php b/scripts/pi-hole/php/header.php index 9ab0d721..ca46c367 100644 --- a/scripts/pi-hole/php/header.php +++ b/scripts/pi-hole/php/header.php @@ -8,6 +8,7 @@ require "scripts/pi-hole/php/auth.php"; require "scripts/pi-hole/php/password.php"; + $scriptname = basename($_SERVER['SCRIPT_FILENAME']); check_cors(); @@ -172,72 +173,83 @@ } ?> - + - + - - + + Pi-hole Admin Console - - - - - - + + + + + + + + - - + + - - - - - + + - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + $token
      "; + echo ""; } ?> - - - - - - - - - - @@ -245,30 +257,35 @@ if($auth) {
      - -