From 628632ff5092f1e3cf6c968d9bdfbd9a24f59541 Mon Sep 17 00:00:00 2001 From: Marcin Zelent Date: Fri, 8 Jan 2021 19:47:37 +0100 Subject: Initial commit --- .eslintrc.json | 51 + .gitignore | 34 + .prettierrc.json | 7 + .vscode/launch.json | 12 + .vscode/settings.json | 3 + README.md | 73 + components/Gallery/Gallery.module.css | 63 + components/Gallery/Gallery.tsx | 80 + components/Map/Map.module.css | 28 + components/Map/Map.tsx | 121 + components/Sidebar/Sidebar.module.css | 54 + components/Sidebar/Sidebar.tsx | 71 + lib/trips.ts | 115 + lib/useEvent.ts | 20 + lib/util.ts | 30 + models/Photo.ts | 31 + models/Trip.ts | 46 + models/index.ts | 4 + next-env.d.ts | 2 + next.config.js | 34 + package-lock.json | 9283 +++++++++++++++++++++++++++++++++ package.json | 47 + pages/_app.tsx | 7 + pages/index.tsx | 80 + public/favicon.ico | Bin 0 -> 9662 bytes screenshots/desktop.png | Bin 0 -> 190852 bytes screenshots/mobile.png | Bin 0 -> 73468 bytes styles/Home.module.css | 49 + styles/globals.css | 19 + trips/.gitignore | 2 + tsconfig.json | 20 + 31 files changed, 10386 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .gitignore create mode 100644 .prettierrc.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100644 components/Gallery/Gallery.module.css create mode 100644 components/Gallery/Gallery.tsx create mode 100644 components/Map/Map.module.css create mode 100644 components/Map/Map.tsx create mode 100644 components/Sidebar/Sidebar.module.css create mode 100644 components/Sidebar/Sidebar.tsx create mode 100644 lib/trips.ts create mode 100644 lib/useEvent.ts create mode 100644 lib/util.ts create mode 100644 models/Photo.ts create mode 100644 models/Trip.ts create mode 100644 models/index.ts create mode 100644 next-env.d.ts create mode 100644 next.config.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 pages/_app.tsx create mode 100644 pages/index.tsx create mode 100644 public/favicon.ico create mode 100644 screenshots/desktop.png create mode 100644 screenshots/mobile.png create mode 100644 styles/Home.module.css create mode 100644 styles/globals.css create mode 100644 trips/.gitignore create mode 100644 tsconfig.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..b8d8c34 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,51 @@ +{ + "extends": [ + "airbnb", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "prettier/react", + "plugin:prettier/recommended", + "prettier/@typescript-eslint", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript" + ], + "plugins": ["@typescript-eslint"], + "parser": "@typescript-eslint/parser", + "env": { "browser": true, "node": true, "es6": true }, + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "prettier/prettier": "error", + "react/prop-types": "off", + "jsx-a11y/anchor-is-valid": "off", + "react/react-in-jsx-scope": "off", + "react/jsx-filename-extension": [ + "error", + { + "extensions": [".js", ".jsx", ".ts", ".tsx"] + } + ], + "import/extensions": [ + "error", + "ignorePackages", + { + "js": "never", + "jsx": "never", + "ts": "never", + "tsx": "never", + "d.ts": "never" + } + ] + }, + "settings": { + "import/extensions": [".js", ".jsx", ".ts", ".tsx", ".d.ts"], + "import/parsers": { + "@typescript-eslint/parser": [".ts", ".tsx", ".d.ts"] + }, + "import/resolver": { + "typescript": {} + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1437c53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..98b83ae --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "semi": true, + "printWidth": 100, + "singleQuote": true, + "trailingComma": "all", + "arrowParens": "always" +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..72cb4c6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "attach", + "name": "Launch Program", + "skipFiles": ["/**"], + "port": 9229 + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..55712c1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..053af27 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# Trip Share + +A web application for sharing trips recorded in the GPX format along with +photos. + +## Preview + +| ![Desktop](./screenshots/desktop.png) | ![Mobile](./screenshots/mobile.png) | +| ------------------------------------- | ----------------------------------- | + +You can also see a demo at https://zelent.net/trips. + +## Description + +The idea of the application came when I wanted to share my bike trips with my +family and friends. I needed an easy way to display the route on a map and the +photos I've taken on the trip. I record my bike trips using +[OSMAnd](https://osmand.net/) navigation app and take photos with the location +saved in the image metadata. + +The application displays the route recorded with GPS in the GPX format on an +interactive map. The photos are displayed as markers in places they have been +taken, and when clicked on, they are opened in a slideshow view. It is usable +both on desktop and mobile. + +The application was developed using [Node.js](https://nodejs.org/), +[TypeScript](https://www.typescriptlang.org/), and +[Next.js](https://nextjs.org/) framework. The pages and components are built +with [React](https://reactjs.org/). The map was created with +[Leaflet](https://leafletjs.com/). + +The app is statically generated. GPX files and photos inside "trips" folder are +processed during build time. The data is converted to HTML and JSON, photos are +stripped of EXIF metadata, resized, and optimized. No requests are made to +external APIs, only map tiles are being downloaded. + +## Running + +To run the application, first install the dependencies: + +``` +npm install +``` + +Then, you can run it in development mode: + +``` +npm run dev +``` + +To build the application use: + +``` +npm run build +``` + +The built files will be in "out" directory. + +### Trips data + +To display the trips, place them in the "trips" folder with the following +structure: + +``` +trips/ +├── trip-1/ +│   ├── trip-1.gpx +│   ├── photo-1.jpg +│   ├── photo-2.jpg +│   ├── photo-3.jpg +├── trip-2/ +│   ├── trip-2.gpx +``` diff --git a/components/Gallery/Gallery.module.css b/components/Gallery/Gallery.module.css new file mode 100644 index 0000000..01e8037 --- /dev/null +++ b/components/Gallery/Gallery.module.css @@ -0,0 +1,63 @@ +.galleryContainer { + padding: 20px; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99999; + background: rgba(0, 0, 0, 0.8); +} + +.photoContainer { + width: 100%; + height: 100%; + padding: 20px; + position: relative; +} + +.photo { + max-width: 100%; + max-height: 100%; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.btn { + position: absolute; + z-index: 99999; + font-size: 2rem; + color: #eee; + background: none; + border: none; + cursor: pointer; + outline: currentcolor none medium; +} + +.btn:hover { + color: #fff; +} + +.arrowLeft { + top: 50%; + left: 0; + transform: translateY(-50%); +} + +.arrowRight { + top: 50%; + right: 0; + transform: translateY(-50%); +} + +.closeBtn { + width: 64px; + height: 64px; + top: 0; + right: 0; + font-size: 4rem; + line-height: 4rem; + font-weight: 300; +} diff --git a/components/Gallery/Gallery.tsx b/components/Gallery/Gallery.tsx new file mode 100644 index 0000000..dfadbc0 --- /dev/null +++ b/components/Gallery/Gallery.tsx @@ -0,0 +1,80 @@ +import { useEffect, useRef } from 'react'; + +import { Photo } from 'models'; +import useEvent from 'lib/useEvent'; +import styles from './Gallery.module.css'; + +interface Props { + currentPhoto: Photo; + handleClose: () => void; + handlePhotoChange: (direction: boolean) => void; +} + +export default function Gallery({ + currentPhoto, + handleClose, + handlePhotoChange, +}: Props): JSX.Element { + const wrapperRef = useRef(null); + + useEffect(() => { + function handleClickOutside(e: MouseEvent) { + if ( + wrapperRef.current && + !wrapperRef.current.contains(e.target) && + (e.target as Node).nodeName !== 'BUTTON' + ) { + handleClose(); + } + } + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [wrapperRef]); + + useEvent('keydown', (e: KeyboardEvent) => { + if (e.key === 'ArrowLeft') { + handlePhotoChange(false); + } else if (e.key === 'ArrowRight') { + handlePhotoChange(true); + } else if (e.key === 'Escape') { + handleClose(); + } + }); + + return ( +
+ +
+ {currentPhoto.name} +
+ + +
+ ); +} diff --git a/components/Map/Map.module.css b/components/Map/Map.module.css new file mode 100644 index 0000000..b13f5d2 --- /dev/null +++ b/components/Map/Map.module.css @@ -0,0 +1,28 @@ +.popup { + width: auto; + min-height: 90%; +} + +.popup .leaflet-popup-content { + margin: 0; +} + +.markerIcon { + border: 2px solid #fff; + border-radius: 2px; + overflow: hidden; +} + +.markerItemCount { + width: 18px; + height: 18px; + display: block; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + border-radius: 10px; + background: #fff; + text-align: center; + font-weight: bold; +} diff --git a/components/Map/Map.tsx b/components/Map/Map.tsx new file mode 100644 index 0000000..44f8ea6 --- /dev/null +++ b/components/Map/Map.tsx @@ -0,0 +1,121 @@ +import { LatLngBounds, DivIcon, Icon } from 'leaflet'; +import { useEffect, useState } from 'react'; +import ReactDom from 'react-dom/server'; +import { MapContainer, Marker, TileLayer, GeoJSON, ZoomControl } from 'react-leaflet'; +import MarkerClusterGroup from 'react-leaflet-markercluster'; + +import { Trip, Photo } from 'models'; +import { distanceBetween } from 'lib/util'; + +import 'leaflet/dist/leaflet.css'; +import styles from './Map.module.css'; + +interface Props { + trip: Trip; + handleMarkerClick: (photo: string) => void; +} + +export default function Map({ trip, handleMarkerClick }: Props): JSX.Element { + const [map, setMap] = useState(null); + + const bounds = trip + ? new LatLngBounds( + [trip.track.bbox[1], trip.track.bbox[0]], + [trip.track.bbox[3], trip.track.bbox[2]], + ) + : new LatLngBounds([75, -145], [-52, 145]); + + function createMarkers(photos: Photo[]): JSX.Element[] { + // cluster photos that are close to each other + const clusters: Photo[][] = []; + for (let i = 0; i < photos.length; i += 1) { + if (clusters.filter((c) => c.includes(photos[i])).length === 0) { + const cluster = [photos[i]]; + for (let j = 0; j < photos.length; j += 1) { + if (photos[i] !== photos[j]) { + const a = [photos[i].latitude, photos[i].longitude]; + const b = [photos[j].latitude, photos[j].longitude]; + const distance = distanceBetween(a, b); + if (distance < 10) cluster.push(photos[j]); + } + } + clusters.push(cluster); + } + } + + // create React elements based on the clusters + const markers = clusters.map((cluster) => { + let Wrapper = ({ children }) => <>{children}; + if (cluster.length > 1) { + Wrapper = ({ children }) => ( + + new DivIcon({ + html: ReactDom.renderToString( + <> + + {markerCluster.getChildCount()} + , + ), + iconSize: [36, 36], + className: styles.markerIcon, + }) + } + > + {children} + + ); + } + + const children = cluster.map((photo) => ( + handleMarkerClick(photo.name) }} + /> + )); + + return {children}; + }); + + return markers; + } + + useEffect(() => { + if (map) { + map.setView(bounds.getCenter()); + map.fitBounds(bounds); + } + }, [trip]); + + return ( + + + + {trip && } + {trip && createMarkers(trip.photos)} + + ); +} diff --git a/components/Sidebar/Sidebar.module.css b/components/Sidebar/Sidebar.module.css new file mode 100644 index 0000000..a3c8a1a --- /dev/null +++ b/components/Sidebar/Sidebar.module.css @@ -0,0 +1,54 @@ +.aside { + min-width: 272px; + height: 100%; + padding: 5px; + display: flex; + flex-direction: column; + border-right: 1px solid #e5e5e5; + box-shadow: -2px 0 10px #000; + z-index: 9999; + background-color: #fff; +} + +.aside h2 { + padding-left: 1.5rem; +} + +.list { + margin: 0; + padding: 0; + list-style: none; + overflow-y: auto; +} + +.listItem { + margin-bottom: 5px; + padding: 1rem 2rem 1rem 1.5rem; + display: block; + border-radius: 10px; + cursor: pointer; + user-select: none; + outline: currentcolor none medium; +} + +.listItem:hover { + background-color: #f5f5f5; +} + +.listItemActive { + background-color: #e9f3ff !important; +} + +@media only screen and (max-width: 500px) { + .aside { + position: absolute; + top: 0; + bottom: 0; + left: -100vw; + transition: left 0.3s ease-in; + } + + .asideOpen { + left: 0; + } +} diff --git a/components/Sidebar/Sidebar.tsx b/components/Sidebar/Sidebar.tsx new file mode 100644 index 0000000..6b0473a --- /dev/null +++ b/components/Sidebar/Sidebar.tsx @@ -0,0 +1,71 @@ +import { useEffect, useRef } from 'react'; + +import { Trip } from 'models'; +import { secondsToTimeString } from 'lib/util'; + +import styles from './Sidebar.module.css'; + +interface Props { + trips: Trip[]; + currentTrip: Trip; + asideOpen: boolean; + handleClose: () => void; + setCurrentTrip: (trip: Trip) => void; +} + +export default function Sidebar({ + trips, + currentTrip, + asideOpen, + handleClose, + setCurrentTrip, +}: Props): JSX.Element { + const wrapperRef = useRef(null); + + useEffect(() => { + function handleClickOutside(e: MouseEvent) { + if (wrapperRef.current && !wrapperRef.current.contains(e.target)) { + handleClose(); + } + } + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [wrapperRef]); + + function handleTripChange(trip: Trip): void { + setCurrentTrip(trip); + handleClose(); + } + + return ( + + ); +} diff --git a/lib/trips.ts b/lib/trips.ts new file mode 100644 index 0000000..6a58d34 --- /dev/null +++ b/lib/trips.ts @@ -0,0 +1,115 @@ +import path from 'path'; +import fs from 'fs'; +import { DOMParser } from 'xmldom'; +import { FeatureCollection, LineString } from 'geojson'; +import { gpx } from '@tmcw/togeojson'; +import gb from 'geojson-bounds'; +import * as ExifReader from 'exifreader'; + +import { Trip, Photo } from 'models'; +import { distanceBetween } from 'lib/util'; + +const tripsDirectory = path.join(process.cwd(), 'trips'); + +// extract photo metadata from EXIF +function getPhotoMetadata(filePath: string) { + const buffer = fs.readFileSync(filePath); + const tags = ExifReader.load(buffer, { expanded: true }); + + return { + latitude: tags.gps.Latitude, + longitude: tags.gps.Longitude, + time: tags.exif.DateTime.description.replace(':', '-').replace(':', '-'), + thumbnail: tags.Thumbnail.base64, + }; +} + +/** + * Reads GPX files and photos from trips folder. + */ +export default function getTripsData(): Trip[] { + // get folder names under /trips + const dirs = fs + .readdirSync(tripsDirectory, { withFileTypes: true }) + .filter((dirent) => dirent.isDirectory()) + .map((dirent) => dirent.name); + const allTripsData = dirs.map((dir: string) => { + const dirPath = path.join(tripsDirectory, dir); + const files = fs.readdirSync(dirPath); + + const gpxFiles = files.filter((f) => f.endsWith('.gpx')); + + // read GPX file as string + const fullPath = path.join(dirPath, gpxFiles[0]); + const fileContents = fs.readFileSync(fullPath, 'utf8'); + const contentsWithoutNS = fileContents.replace(/\sxmlns[^"]+"[^"]+"/g, ''); + + // create DOM from string + const doc = new DOMParser().parseFromString(contentsWithoutNS); + + // convert GPX to GeoJSON + const track: FeatureCollection = gpx(doc); + + // add bounding box + track.bbox = [gb.xMin(track), gb.yMin(track), gb.xMax(track), gb.yMax(track)]; + + const { coordTimes } = track.features[0].properties; + + // time of the first point + const start = coordTimes[0]; + + // time of the last point + const end = coordTimes[coordTimes.length - 1]; + + // total duration in seconds + const duration = (new Date(end).getTime() - new Date(start).getTime()) / 1000; + + // distance and speed + let totalDistance = 0; + const speeds = []; + const coords = (track.features[0].geometry as LineString).coordinates; + + for (let i = 0; i < coords.length - 1; i += 1) { + const a = [coords[i][1], coords[i][0]]; + const b = [coords[i + 1][1], coords[i + 1][0]]; + const distance = distanceBetween(a, b); + if (distance > 0) { + totalDistance += distance; + const timeBetween = + new Date(coordTimes[i + 1]).getTime() - new Date(coordTimes[i]).getTime(); + speeds.push(distance / timeBetween); + } + } + + // total distance in km + const distance = Math.floor(totalDistance / 10) / 100; + + // average speed in km/h + const speedMps = speeds.reduce((acc, val) => acc + val) / speeds.length; + const speed = Math.floor(speedMps * 3600 * 100) / 100; + + // photos + const photoFiles = files.filter((f) => f.endsWith('.jpg')); + const photos: Photo[] = photoFiles.map((p) => { + // eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires + const { src } = require(`trips/${dir}/${p}`); + return { + name: p, + src, + ...getPhotoMetadata(path.join(dirPath, p)), + }; + }); + + const trip: Trip = { name: dir, track, distance, start, end, duration, speed, photos }; + + return trip; + }); + + // sort trips by name + return allTripsData.sort((a, b) => { + if (a.name < b.name) { + return 1; + } + return -1; + }); +} diff --git a/lib/useEvent.ts b/lib/useEvent.ts new file mode 100644 index 0000000..70d51b1 --- /dev/null +++ b/lib/useEvent.ts @@ -0,0 +1,20 @@ +import { useEffect } from 'react'; + +/** + * A hook for creating event handlers. + */ +export default function useEvent( + event: string, + handler: (e: KeyboardEvent | MouseEvent) => void, + passive = false, +): void { + useEffect(() => { + // initiate the event handler + window.addEventListener(event, handler, passive); + + // this will clean up the event every time the component is re-rendered + return function cleanup() { + window.removeEventListener(event, handler); + }; + }); +} diff --git a/lib/util.ts b/lib/util.ts new file mode 100644 index 0000000..5a00aed --- /dev/null +++ b/lib/util.ts @@ -0,0 +1,30 @@ +/** + * Converts time in seconds to HH:mm format. + * @param time Time to convert in seconds. + */ +export function secondsToTimeString(time: number): string { + const h = Math.floor(time / 3600); + const m = Math.floor((time % 3600) / 60); + + return `${h < 10 ? `0${h}` : h}:${m < 10 ? `0${m}` : m}`; +} + +/** + * Calculates distance between two geographical points. + * @param latlng1 Coordinates of the first point. + * @param latlng2 Coordinates of the second point. + */ +export function distanceBetween(latlng1: number[], latlng2: number[]): number { + const R = 6371000; + const rad = Math.PI / 180; + const lat1 = latlng1[0] * rad; + const lat2 = latlng2[0] * rad; + const sinDLat = Math.sin(((latlng2[0] - latlng1[0]) * rad) / 2); + const sinDLon = Math.sin(((latlng2[1] - latlng1[1]) * rad) / 2); + const a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon; + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + + return R * c; +} + +export default { secondsToTimeString, distanceBetween }; diff --git a/models/Photo.ts b/models/Photo.ts new file mode 100644 index 0000000..f40d492 --- /dev/null +++ b/models/Photo.ts @@ -0,0 +1,31 @@ +export default interface Photo { + /** + * Name of the photo or the file. + */ + name: string; + + /** + * Path to the photo. + */ + src: string; + + /** + * Latitude where the photo was taken. + */ + latitude: number; + + /** + * Logitude where the photo was taken. + */ + longitude: number; + + /** + * Date and time when the photo was taken. + */ + time: string; + + /** + * Photo thumnnail. + */ + thumbnail: string; +} diff --git a/models/Trip.ts b/models/Trip.ts new file mode 100644 index 0000000..cc01cda --- /dev/null +++ b/models/Trip.ts @@ -0,0 +1,46 @@ +import { GeoJsonObject } from 'geojson'; +import Photo from './Photo'; + +export default interface Trip { + /** + * Name of the trip. + */ + name: string; + + /** + * Total distance made during the trip. + */ + distance: number; + + /** + * Date and time of the beginning of the trip. + * This property is a string because Date is not serializable in Next.js. + */ + start: string; + + /** + * Date and time of the end of the trip. + * This property is a string because Date is not serializable in Next.js. + */ + end: string; + + /** + * Total duration of the trip in seconds. + */ + duration: number; + + /** + * Average speed in km/h. + */ + speed: number; + + /** + * GeoJSON object representing waypoints of the trip + */ + track: GeoJsonObject; + + /** + * Photos taken during the trip. + */ + photos: Photo[]; +} diff --git a/models/index.ts b/models/index.ts new file mode 100644 index 0000000..764b342 --- /dev/null +++ b/models/index.ts @@ -0,0 +1,4 @@ +import Trip from './Trip'; +import Photo from './Photo'; + +export type { Trip, Photo }; diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..7b7aa2c --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..edadc14 --- /dev/null +++ b/next.config.js @@ -0,0 +1,34 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const withPlugins = require('next-compose-plugins'); +const optimizedImages = require('next-optimized-images'); +// eslint-disable-next-line import/no-extraneous-dependencies +const sharp = require('responsive-loader/sharp'); + +module.exports = withPlugins( + [ + [ + optimizedImages, + { + defaultImageLoader: 'responsive-loader', + handleImages: ['jpeg', 'png', 'svg', 'webp', 'gif'], + optimizeImages: true, + optimizeImagesInDev: true, + responsive: { + adapter: sharp, + quality: 75, + size: 1920, + }, + }, + ], + ], + { + webpack: (config) => { + config.module.rules.push({ + test: /\.gpx/, + use: 'raw-loader', + }); + + return config; + }, + }, +); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a1ae297 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9283 @@ +{ + "name": "trip-share", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@ampproject/toolbox-core": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@ampproject/toolbox-core/-/toolbox-core-2.7.2.tgz", + "integrity": "sha512-deQiuOghOShoEBoTIDNsSER5gMC6qZfVqYKvlQYcQ+OxKR7J3FtA5XDz98UQsuWx1EB2x2hivrpC6G9BQaXMHw==", + "requires": { + "lru-cache": "6.0.0", + "node-fetch": "2.6.1" + } + }, + "@ampproject/toolbox-optimizer": { + "version": "2.7.0-alpha.1", + "resolved": "https://registry.npmjs.org/@ampproject/toolbox-optimizer/-/toolbox-optimizer-2.7.0-alpha.1.tgz", + "integrity": "sha512-2wTvOyM6GP6FrYQzxSQCg43STo1jMRGeDKa6YUkYXYH9fm9Wbt2wTRx+ajjb48JQ6WwUnGwga1MhQhVFzRQ+wQ==", + "requires": { + "@ampproject/toolbox-core": "^2.6.0", + "@ampproject/toolbox-runtime-version": "^2.7.0-alpha.1", + "@ampproject/toolbox-script-csp": "^2.5.4", + "@ampproject/toolbox-validator-rules": "^2.5.4", + "abort-controller": "3.0.0", + "cross-fetch": "3.0.5", + "cssnano-simple": "1.2.0", + "dom-serializer": "1.0.1", + "domhandler": "3.0.0", + "domutils": "2.1.0", + "htmlparser2": "4.1.0", + "https-proxy-agent": "5.0.0", + "lru-cache": "6.0.0", + "node-fetch": "2.6.0", + "normalize-html-whitespace": "1.0.0", + "postcss": "7.0.32", + "postcss-safe-parser": "4.0.2", + "terser": "5.1.0" + }, + "dependencies": { + "cssnano-simple": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cssnano-simple/-/cssnano-simple-1.2.0.tgz", + "integrity": "sha512-pton9cZ70/wOCWMAbEGHO1ACsW1KggTB6Ikj7k71uOEsz6SfByH++86+WAmXjRSc9q/g9gxkpFP9bDX9vRotdA==", + "requires": { + "cssnano-preset-simple": "1.2.0", + "postcss": "^7.0.32" + } + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "postcss": { + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + } + } + }, + "@ampproject/toolbox-runtime-version": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@ampproject/toolbox-runtime-version/-/toolbox-runtime-version-2.7.2.tgz", + "integrity": "sha512-BKDl29i/cvC0xtrUHnF2YR25gMfyVnXCaV1ZaMDNcPNRJGbBSNQtW6eZt9+rPoV/hKpFxyJia30ECw42FVhh9g==", + "requires": { + "@ampproject/toolbox-core": "^2.7.2" + } + }, + "@ampproject/toolbox-script-csp": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/@ampproject/toolbox-script-csp/-/toolbox-script-csp-2.5.4.tgz", + "integrity": "sha512-+knTYetI5nWllRZ9wFcj7mYxelkiiFVRAAW/hl0ad8EnKHMH82tRlk40CapEnUHhp6Er5sCYkumQ8dngs3Q4zQ==" + }, + "@ampproject/toolbox-validator-rules": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@ampproject/toolbox-validator-rules/-/toolbox-validator-rules-2.7.2.tgz", + "integrity": "sha512-/XNa5nhyZl8ET63HQv73AjgEZN03YMBZVZwZ62luxsuEsfzpVzs/tU/RaOHCnL2EuRyaAX95O7GO3Gyxp8z79g==", + "requires": { + "node-fetch": "2.6.1" + } + }, + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/runtime": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz", + "integrity": "sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ==", + "dev": true, + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@eslint/eslintrc": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", + "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + }, + "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 + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + } + } + }, + "@hapi/accept": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-5.0.1.tgz", + "integrity": "sha512-fMr4d7zLzsAXo28PRRQPXR1o2Wmu+6z+VY1UzDp0iFo13Twj8WePakwXBiqn3E1aAlTpSNzCXdnnQXFhst8h8Q==", + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/boom": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.1.tgz", + "integrity": "sha512-VNR8eDbBrOxBgbkddRYIe7+8DZ+vSbV6qlmaN2x7eWjsUjy2VmQgChkOKcVZIeupEZYj+I0dqNg430OhwzagjA==", + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/hoek": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.1.0.tgz", + "integrity": "sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw==" + }, + "@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==", + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + }, + "dependencies": { + "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=" + } + } + }, + "@next/env": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@next/env/-/env-10.0.3.tgz", + "integrity": "sha512-xjJt2VXoSxAydskmt77nJuEtRL782E4ltaj5JtMzJ8YkNUMMu3d5ktpCR+Q3INKHF/RY6zHJ9QzyE3/s1ikbNg==" + }, + "@next/polyfill-module": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-10.0.3.tgz", + "integrity": "sha512-JaiycQZZbqViaMZgRGYcPIdCPDz+qRnqEGxbhQlrxyPaBaOtsrAEkGf1SS2wJZKa/ncxqWHMfSvizDcGcz/ygQ==" + }, + "@next/react-dev-overlay": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-10.0.3.tgz", + "integrity": "sha512-ykiKeUhTsMRoyyYnx4jM8xeOPfKGqQ7xgx2dNXOu4tbPpdivzjJp2+K6+xnqhTmZ7uxfFBV+b1OE1ZzA8qyX5Q==", + "requires": { + "@babel/code-frame": "7.10.4", + "ally.js": "1.4.1", + "anser": "1.4.9", + "chalk": "4.0.0", + "classnames": "2.2.6", + "data-uri-to-buffer": "3.0.0", + "shell-quote": "1.7.2", + "source-map": "0.8.0-beta.0", + "stacktrace-parser": "0.1.10", + "strip-ansi": "6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "requires": { + "whatwg-url": "^7.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@next/react-refresh-utils": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.0.3.tgz", + "integrity": "sha512-XtzzPX2R4+MIyu1waEQUo2tiNwWVEkmObA6pboRCDTPOs4Ri8ckaIE08lN5A5opyF6GVN+IEq/J8KQrgsePsZQ==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@react-leaflet/core": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-1.0.2.tgz", + "integrity": "sha512-QbleYZTMcgujAEyWGki8Lx6cXQqWkNtQlqf5c7NImlIp8bKW66bFpez/6EVatW7+p9WKBOEOVci/9W7WW70EZg==" + }, + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" + }, + "@tmcw/togeojson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tmcw/togeojson/-/togeojson-4.2.0.tgz", + "integrity": "sha512-kjUJemmidx4SS9QT4P5nUkS6s9IE0xpqwaWcnDd7q0McFhfRiAHJMEVarxcFXecvZAIyPt9+974NfOGr7/cKfg==" + }, + "@types/geojson": { + "version": "7946.0.7", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz", + "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/leaflet": { + "version": "1.5.19", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.5.19.tgz", + "integrity": "sha512-ZAKqfvdU/+KFoCpf8aUba09F8mfSc8R2esq++Cha3E2DgwS5K/I/4eJ+0JylrVHZivgY7PSAeXFv/izP+81/MQ==", + "dev": true, + "requires": { + "@types/geojson": "*" + } + }, + "@types/node": { + "version": "14.14.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz", + "integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true + }, + "@types/react": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz", + "integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.10.0.tgz", + "integrity": "sha512-h6/V46o6aXpKRlarP1AiJEXuCJ7cMQdlpfMDrcllIgX3dFkLwEBTXAoNP98ZoOmqd1xvymMVRAI4e7yVvlzWEg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.10.0", + "@typescript-eslint/scope-manager": "4.10.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.10.0.tgz", + "integrity": "sha512-opX+7ai1sdWBOIoBgpVJrH5e89ra1KoLrJTz0UtWAa4IekkKmqDosk5r6xqRaNJfCXEfteW4HXQAwMdx+jjEmw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.10.0", + "@typescript-eslint/types": "4.10.0", + "@typescript-eslint/typescript-estree": "4.10.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.10.0.tgz", + "integrity": "sha512-amBvUUGBMadzCW6c/qaZmfr3t9PyevcSWw7hY2FuevdZVp5QPw/K76VSQ5Sw3BxlgYCHZcK6DjIhSZK0PQNsQg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.10.0", + "@typescript-eslint/types": "4.10.0", + "@typescript-eslint/typescript-estree": "4.10.0", + "debug": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.10.0.tgz", + "integrity": "sha512-WAPVw35P+fcnOa8DEic0tQUhoJJsgt+g6DEcz257G7vHFMwmag58EfowdVbiNcdfcV27EFR0tUBVXkDoIvfisQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.10.0", + "@typescript-eslint/visitor-keys": "4.10.0" + } + }, + "@typescript-eslint/types": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.10.0.tgz", + "integrity": "sha512-+dt5w1+Lqyd7wIPMa4XhJxUuE8+YF+vxQ6zxHyhLGHJjHiunPf0wSV8LtQwkpmAsRi1lEOoOIR30FG5S2HS33g==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.10.0.tgz", + "integrity": "sha512-mGK0YRp9TOk6ZqZ98F++bW6X5kMTzCRROJkGXH62d2azhghmq+1LNLylkGe6uGUOQzD452NOAEth5VAF6PDo5g==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.10.0", + "@typescript-eslint/visitor-keys": "4.10.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.10.0.tgz", + "integrity": "sha512-hPyz5qmDMuZWFtHZkjcCpkAKHX8vdu1G3YsCLEd25ryZgnJfj6FQuJ5/O7R+dB1ueszilJmAFMtlU4CA6se3Jg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.10.0", + "eslint-visitor-keys": "^2.0.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, + "adjust-sourcemap-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz", + "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==", + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" + }, + "ally.js": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/ally.js/-/ally.js-1.4.1.tgz", + "integrity": "sha1-n7fmuljvrE7pExyymqnuO1QLzx4=", + "requires": { + "css.escape": "^1.5.0", + "platform": "1.3.3" + } + }, + "anser": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.9.tgz", + "integrity": "sha512-AI+BjTeGt2+WFk4eWcqbQ7snZpDBt8SaLlj0RT2h5xfdWaiy51OjYvqwMrNzJLGy8iOAL6nKDITWO+rd4MkYEA==" + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "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==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==" + }, + "archive-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", + "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=", + "requires": { + "file-type": "^4.2.0" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "