diff --git a/.gitignore b/.gitignore index 0689074a82..9c33848bc3 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ *.tar *.zip !regional_areas.zip +!qaqc_well_data.zip # Logs and databases # ###################### diff --git a/app/backend/aquifers/fixtures/aquifers.json b/app/backend/aquifers/fixtures/aquifers.json index 2ebf4a9928..ec8128340e 100644 --- a/app/backend/aquifers/fixtures/aquifers.json +++ b/app/backend/aquifers/fixtures/aquifers.json @@ -999,7 +999,13 @@ "hydro_fracturing_yield_increase": null, "decommission_sealant_material": "CONCRETE", "decommission_backfill_material": "test", - "geom": "POINT(-125.376319 52.528545)" + "geom": "POINT(-125.376319 52.528545)", + "distance_to_pid": "123.45", + "geocode_distance": "543.21", + "score_address": "78.90", + "score_city": "56.78", + "cross_referenced": false, + "natural_resource_region": "Northeast" } }, { @@ -1124,7 +1130,13 @@ "hydro_fracturing_yield_increase": null, "decommission_sealant_material": "CONCRETE", "decommission_backfill_material": "test", - "geom": "POINT(-125.351850 52.461419)" + "geom": "POINT(-125.351850 52.461419)", + "distance_to_pid": "234.56", + "geocode_distance": "654.32", + "score_address": "89.01", + "score_city": "67.89", + "cross_referenced": true, + "natural_resource_region": "Northeast" } }, { @@ -1249,7 +1261,13 @@ "hydro_fracturing_yield_increase": null, "decommission_sealant_material": "CONCRETE", "decommission_backfill_material": "test", - "geom": "POINT(-125.361842 52.476454)" + "geom": "POINT(-125.361842 52.476454)", + "distance_to_pid": "345.67", + "geocode_distance": "765.43", + "score_address": "90.12", + "score_city": "78.90", + "cross_referenced": false, + "natural_resource_region": "Northeast" } }, { @@ -1373,7 +1391,13 @@ "hydro_fracturing_yield_increase": null, "decommission_sealant_material": "CONCRETE", "decommission_backfill_material": "test", - "geom": "POINT(-125.381245 52.466459)" + "geom": "POINT(-125.381245 52.466459)", + "distance_to_pid": "456.78", + "geocode_distance": "876.54", + "score_address": "12.34", + "score_city": "89.01", + "cross_referenced": true, + "natural_resource_region": "Northeast" } }, { diff --git a/app/backend/gwells/fixtures/wellsearch.json b/app/backend/gwells/fixtures/wellsearch.json index b493fb2f6c..fca692d087 100644 --- a/app/backend/gwells/fixtures/wellsearch.json +++ b/app/backend/gwells/fixtures/wellsearch.json @@ -845,7 +845,15 @@ "decommission_method": null, "decommission_details": null, "water_quality_characteristics": [], - "geom": "POINT(-122.540000 49.260000)" + "geom": "POINT(-122.540000 49.260000)", + "distance_to_pid": "123.45", + "geocode_distance": "543.21", + "score_address": "78.90", + "score_city": "56.78", + "cross_referenced": false, + "cross_referenced_date": "2023-02-08T17:06:47.229Z", + "cross_referenced_by": "DATA_LOAD_USER", + "natural_resource_region": "Northeast" } }, { @@ -966,7 +974,13 @@ "drawdown": "190.00", "hydro_fracturing_performed": false, "hydro_fracturing_yield_increase": null, - "geom": "POINT(-122.540000 49.200000)" + "geom": "POINT(-122.540000 49.200000)", + "distance_to_pid": "234.56", + "geocode_distance": "654.32", + "score_address": "89.01", + "score_city": "67.89", + "cross_referenced": true, + "natural_resource_region": "Northeast" } }, { @@ -1087,7 +1101,13 @@ "drawdown": null, "hydro_fracturing_performed": false, "hydro_fracturing_yield_increase": null, - "geom": "POINT(-122.580000 49.230000)" + "geom": "POINT(-122.580000 49.230000)", + "distance_to_pid": "345.67", + "geocode_distance": "765.43", + "score_address": "90.12", + "score_city": "78.90", + "cross_referenced": false, + "natural_resource_region": "Northeast" } }, { @@ -1208,7 +1228,13 @@ "drawdown": null, "hydro_fracturing_performed": false, "hydro_fracturing_yield_increase": null, - "geom": "POINT(-122.590000 49.250000)" + "geom": "POINT(-122.590000 49.250000)", + "distance_to_pid": "456.78", + "geocode_distance": "876.54", + "score_address": "12.34", + "score_city": "89.01", + "cross_referenced": true, + "natural_resource_region": "Northeast" } }, { @@ -1332,7 +1358,13 @@ "hydro_fracturing_yield_increase": null, "decommission_sealant_material": "CONCRETE", "decommission_backfill_material": "test", - "geom": "POINT(-125.360830 52.456449)" + "geom": "POINT(-125.360830 52.456449)", + "distance_to_pid": "567.89", + "geocode_distance": "987.65", + "score_address": "23.45", + "score_city": "90.12", + "cross_referenced": false, + "natural_resource_region": "South Coast" } }, { @@ -1479,7 +1511,13 @@ ], "decommission_backfill_material": null, "decommission_sealant_material": null, - "geom": null + "geom": null, + "distance_to_pid": "678.90", + "geocode_distance": "109.87", + "score_address": "34.56", + "score_city": "12.34", + "cross_referenced": true, + "natural_resource_region": "Kootenay" } }, { diff --git a/app/backend/gwells/settings/__init__.py b/app/backend/gwells/settings/__init__.py index bbef626e71..d1de1ed151 100644 --- a/app/backend/gwells/settings/__init__.py +++ b/app/backend/gwells/settings/__init__.py @@ -12,6 +12,7 @@ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os +import sys import datetime import logging.config from pathlib import Path @@ -23,6 +24,7 @@ BASE_DIR = str(Path(__file__).parents[2]) +TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test' # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ diff --git a/app/backend/gwells/utils.py b/app/backend/gwells/utils.py index 69753110ab..8c882d8bbf 100644 --- a/app/backend/gwells/utils.py +++ b/app/backend/gwells/utils.py @@ -20,59 +20,48 @@ def isPointInsideBC(latitude, longitude): return False -def geocode_bc_location(options={}): - """ - Makes an HTTP call to the BC Physical Address Geocoder API - (https://www2.gov.bc.ca/gov/content/data/geographic-data-services/location-services/geocoder) - using any options provided as query string parameters. (the 'options' - parameter supports any query string parameter supported by the "addresses.json" - endpoint. - If the address is successfully geocoded then this method returns a - django.contrib.gis.geos.Point object corresponding to the first result. - If a HTTP error occurs during - communication with the remote API then an HTTPError exception is - raised. If the API call succeeds but does not find a coordinate - matching the given address_string, then a ValueError is raised. - :param options: typical options are: - { - "addressString": "101 main st.", - "localityName": "Kelowna" - } - """ +def setup_parameters(options): default_options = { - "provinceCode": "BC", - "outputSRS": 4326, - "maxResults": 1, - "minScore": 65 + "provinceCode": "BC", + "outputSRS": 4326, + "maxResults": 1, + "minScore": 65 } - params = {} - params.update(default_options) - params.update(options) + return {**default_options, **options} - url = "https://geocoder.api.gov.bc.ca/addresses.json" - +def perform_api_request(url, params): try: resp = requests.get(url, params=params, timeout=10) resp.raise_for_status() - except HTTPError as e: - #caught and re-raised to be clear ane explicit which exceptions - #this method may cause + return resp + except requests.HTTPError as e: raise e - features = [] - - try: - features = resp.json().get('features') - except AttributeError as e: +def process_response(response): + try: + features = response.json().get('features') + if not features: + raise ValueError("Unable to geocode address") + return features[0] + except AttributeError: raise ValueError("Unable to geocode address") - if not len(features): - raise ValueError("Unable to geocode address") - - first_feature = features[0] +def geocode_bc_location(options={}): + """ + Performs an HTTP request to the BC Physical Address Geocoder API, + returning a django.contrib.gis.geos.Point for the first result. Supports query + string parameters via the 'options' argument. Raises HTTPError for + communication issues and ValueError if no matching coordinate is found. + Example 'options': {"addressString": "101 main st.", "localityName": "Kelowna"}. + """ + params = setup_parameters(options) + url = "https://geocoder.api.gov.bc.ca/addresses.json" + response = perform_api_request(url, params) + first_feature = process_response(response) + try: point = GEOSGeometry(json.dumps(first_feature.get("geometry", {}))) - except TypeError as e: + except TypeError: raise ValueError("Unable to geocode address") return point \ No newline at end of file diff --git a/app/backend/requirements.txt b/app/backend/requirements.txt index daba280b3d..ed99f4db0f 100644 --- a/app/backend/requirements.txt +++ b/app/backend/requirements.txt @@ -28,3 +28,6 @@ geojson==2.4.1 MarkupSafe>=2.0.1 djangorestframework-simplejwt==4.4.0 pyjwt>=2.0,<=2.4.0 +thefuzz==0.19.0 +geopandas==0.9.0 +pyproj==3.0.1 diff --git a/app/backend/wells/apps.py b/app/backend/wells/apps.py index 759bb7c0e5..99072019b9 100644 --- a/app/backend/wells/apps.py +++ b/app/backend/wells/apps.py @@ -33,3 +33,5 @@ class WellsConfig(AppConfig): def ready(self): post_migrate.connect(post_migration_callback, sender=self) + import wells.signals #noqa + import wells.utils #noqa diff --git a/app/backend/wells/constants.py b/app/backend/wells/constants.py index 1a6321629b..fefc90d808 100644 --- a/app/backend/wells/constants.py +++ b/app/backend/wells/constants.py @@ -28,3 +28,36 @@ WELL_TAGS = [] WELL_TAGS.extend(WELL_TAGS_PUBLIC.copy()) WELL_TAGS.extend(WELL_TAGS_PRIVATE.copy()) + +# bc geocoder endpoint of interest +GEOCODER_ENDPOINT = "https://geocoder.api.gov.bc.ca/sites/nearest.json" +ADDRESS_COLUMNS = [ + "fullAddress", + "siteName", + "unitDesignator", + "unitNumber", + "unitNumberSuffix", + "civicNumber", + "civicNumberSuffix", + "streetName", + "streetType", + "isStreetTypePrefix", + "streetDirection", + "isStreetDirectionPrefix", + "streetQualifier", + "localityName", + "localityType", + "electoralArea", + "provinceCode", + "locationPositionalAccuracy", + "locationDescriptor", + "siteID", + "blockID", + "fullSiteDescriptor", + "accessNotes", + "siteStatus", + "siteRetireDate", + "changeDate", + "isOfficial", + "distance", +] diff --git a/app/backend/wells/filters.py b/app/backend/wells/filters.py index 147abce479..b5ab47752b 100644 --- a/app/backend/wells/filters.py +++ b/app/backend/wells/filters.py @@ -14,16 +14,18 @@ import json import logging from collections import OrderedDict +from datetime import datetime, timedelta from django import forms from django.core.exceptions import FieldDoesNotExist from django.db import connection +from django.contrib.gis.db import models from django.http import HttpRequest, QueryDict from django.contrib.gis.geos import GEOSException, Polygon, GEOSGeometry, Point from django.contrib.gis.gdal import GDALException from django.contrib.gis.db.models.functions import Transform from django.contrib.gis.measure import D -from django.db.models import Max, Min, Q, QuerySet +from django.db.models import Max, Min, Q, QuerySet, Subquery, OuterRef from django_filters import rest_framework as filters from django_filters.widgets import BooleanWidget from rest_framework.exceptions import ValidationError @@ -41,7 +43,10 @@ WellAttachment, PumpingTestDescriptionCode, BoundaryEffectCode, - AnalysisMethodCode + AnalysisMethodCode, + LithologyDescription, + Casing, + ActivitySubmission ) from wells.constants import WELL_TAGS @@ -828,3 +833,313 @@ def filter_queryset(self, request, queryset, view): return queryset.order_by(*ordering) return queryset + + +class WellQaQcFilterBackend(filters.DjangoFilterBackend): + """ + Custom well list filtering logic for the QaQc Dashboard. + allows additional 'filter_group' params. + """ + def parse_datetime_with_fallback(self, date_str): + try: + # First, try to parse with full datetime format + return datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S.%fZ") + except ValueError: + # If it fails, parse with date-only format and assume midnight + return datetime.strptime(date_str, "%Y-%m-%d") + + + def filter_queryset(self, request, queryset, view): + try: + filter_groups = request.query_params.getlist('filter_group', []) + for group in filter_groups: + try: + group_params = json.loads(group) + except ValueError as exc: + raise ValidationError({ + 'filter_group': 'Error parsing JSON data: {}'.format(exc), + }) + + if not group_params: + continue + + q_objects = Q() + q_fields = [ + 'well_tag_number', 'identification_plate_number', 'natural_resource_region', + 'cross_referenced_by', 'create_user', 'update_user', 'internal_comments', + 'comments' + ] + date_fields = [ + 'create_date_before', 'create_date_after', + 'update_date_before', 'update_date_after', + 'cross_referenced_date_before', 'cross_referenced_date_after' + ] + + for field, value in group_params.items(): + if field in q_fields and value != 'null': + q_objects &= Q(**{f'{field}__icontains': value}) + + # Set filter date fields + elif field in date_fields: + suffix = field.split('_')[-1] # after or before + date_field = '_'.join(field.split('_')[:-1]) # remove _after or _before + # Use the new parsing function with fallback + date_value = self.parse_datetime_with_fallback(value) + if suffix == 'after': + # Set to the start of the day if only a date is provided + if len(value) <= 10: # YYYY-MM-DD is 10 characters + start_of_day = date_value + else: + start_of_day = date_value + q_objects &= Q(**{f'{date_field}__gte': start_of_day}) + elif suffix == 'before': + # Set to the end of the day if only a date is provided + if len(value) <= 10: # YYYY-MM-DD is 10 characters + end_of_day = datetime.combine(date_value, datetime.max.time()) + else: + end_of_day = date_value + q_objects &= Q(**{f'{date_field}__lte': end_of_day}) + + # Apply range filters + elif field.endswith('min') or field.endswith('max'): + range_field = '_'.join(field.split('_')[:-1]) # remove _min or _max + suffix = field.split('_')[-1] # min or max + if suffix == 'min': + q_objects &= Q(**{f'{range_field}__gte': value}) + elif suffix == 'max': + q_objects &= Q(**{f'{range_field}__lte': value}) + + # Directly handle special cases for fields like latitude and longitude + elif field in ['latitude', 'longitude'] and value == 'null': + q_objects &= Q(**{'geom__isnull': True}) + + elif field == 'intended_water_use': + q_objects &= Q(intended_water_use__intended_water_use_code=value) + + # Person responsible checks + elif field == 'person_responsible_name' and value != 'null': + q_objects &= ( + Q(person_responsible__first_name__icontains=value) | + Q(person_responsible__surname__icontains=value) + ) + + elif field == 'person_responsible_name' and value == 'null': + q_objects &= (Q(person_responsible__isnull=True) | Q(person_responsible__first_name__isnull=True) | + Q(person_responsible__first_name='') | Q(person_responsible__first_name=' ')) + + elif field == 'company_of_person_responsible_name' and value != 'null': + q_objects &= Q(company_of_person_responsible__name__icontains=value) + + elif field == 'company_of_person_responsible_name' and value == 'null': + q_objects &= (Q(company_of_person_responsible__isnull=True) | + Q(company_of_person_responsible__name__isnull=True) | + Q(company_of_person_responsible__name='') | Q(company_of_person_responsible__name=' ')) + + elif field == 'well_class': + q_objects &= Q(well_class__well_class_code=value) + + elif field == 'well_subclass' and value != '00000000-0000-0000-0000-000000000000': + q_objects &= Q(well_subclass__well_subclass_guid=value) + + # Check for null 'well_subclass' + elif field == 'well_subclass' and value == '00000000-0000-0000-0000-000000000000': + q_objects &= Q(well_subclass__well_subclass_guid__isnull=True) + + # Check for null or empty 'aquifer_lithology' + elif field == 'aquifer_lithology' and value == 'null': + # Subquery to get the last lithology description's raw data for each well + last_lithology_raw_data = Subquery( + LithologyDescription.objects.filter( + well=OuterRef('pk') + ).order_by('-end').values('lithology_raw_data')[:1] + ) + queryset = queryset.annotate( + last_lithology_raw_data=last_lithology_raw_data + ) + q_objects &= ( + Q(last_lithology_raw_data__isnull=True) | + Q(last_lithology_raw_data='') | + Q(last_lithology_raw_data=' ') + ) + + # Check for null or empty 'casing_diameter' using the subquery + elif field == 'diameter' and value == 'null': + # Subquery to get the last casing's diameter for each well + last_casing_diameter = Subquery( + Casing.objects.filter( + well=OuterRef('pk') + ).order_by('-end').values('diameter')[:1] + ) + queryset = queryset.annotate( + last_casing_diameter=last_casing_diameter + ) + q_objects &= Q(last_casing_diameter__isnull=True) + + elif field == 'well_activity_type': + # Subquery to get the well_activity_type__code of the latest ActivitySubmission + # for each well, excluding 'STAFF_EDIT' + latest_well_activity_type_code = Subquery( + ActivitySubmission.objects.filter( + well=OuterRef('pk') # Reference the outer Well's primary key + ).exclude( + well_activity_type__code="STAFF_EDIT" + ).order_by( + '-work_end_date' # Ensure the latest activity comes first + ).values( + 'well_activity_type__code' # Select the well_activity_type__code field + )[:1] # Limit to the first (latest) entry + ) + # Annotate the queryset with the result of the subquery + queryset = queryset.annotate( + latest_well_activity_type_code=latest_well_activity_type_code + ) + # Apply filters based on the annotated 'latest_well_activity_type_code' + if value == 'null': + q_objects &= Q(latest_well_activity_type_code__isnull=True) + else: + q_objects &= Q(latest_well_activity_type_code=value) + + elif field == 'work_start_date' and value == 'null': + last_activity_start_date = Subquery( + ActivitySubmission.objects.filter( + well=OuterRef('pk') + ).order_by('-work_end_date').values('work_start_date')[:1] + ) + queryset = queryset.annotate( + last_work_start_date=last_activity_start_date + ) + q_objects &= Q(last_work_start_date__isnull=True) + + elif field == 'work_end_date' and value == 'null': + last_activity_end_date = Subquery( + ActivitySubmission.objects.filter( + well=OuterRef('pk') + ).order_by('-work_end_date').values('work_end_date')[:1] + ) + queryset = queryset.annotate( + last_work_end_date=last_activity_end_date + ) + q_objects &= Q(last_work_end_date__isnull=True) + + # This acts as a catch all for all null field checks + elif value == 'null': + # Check if the field exists in the model + try: + field_obj = queryset.model._meta.get_field(field) + except models.FieldDoesNotExist: + continue + + # Now handling CharField, including checks for empty strings and spaces + if isinstance(field_obj, models.CharField): + q_objects &= (Q(**{f'{field}__isnull': True}) | Q(**{f'{field}': ''}) | Q(**{f'{field}': ' '})) + else: + # For other field types, just check for null + q_objects &= Q(**{f'{field}__isnull': True}) + + # Apply the combined Q object filters to the queryset + queryset = queryset.filter(q_objects) + + # Apply any custom sorting + queryset = self.sort_ordering(request, queryset) + + except Exception as e: + print(e) + return queryset + + def sort_ordering(self, request, queryset): + # Apply custom ordering on the calculated annotation fields + # If not a custom field set here, ordering will fall back + # to WellListOrderingFilter class, set in serializer + # Get ordering params + order_value = request.query_params.get('ordering', 'well_tag_number') + order_field = order_value.lstrip('-') + + # Handle custom ordering for well_subclass + if order_field == 'well_subclass': + # Annotate queryset with the description of the well subclass for ordering + queryset = queryset.annotate( + well_subclass_description=models.F('well_subclass__description') + ) + + # Determine if we are ordering in descending order + if order_value.startswith('-'): + order_value = '-well_subclass_description' + else: + order_value = 'well_subclass_description' + + # Return the queryset ordered by the annotated well subclass description + return queryset.order_by(order_value) + + if order_field not in ['aquifer_lithology', 'diameter', 'well_activity_type', + 'work_start_date', 'work_end_date']: + return queryset + + # Mapping of fields to their related order fields + related_order_mapping = { + 'aquifer_lithology': 'last_lithology_raw_data', + 'diameter': 'last_casing_diameter', + 'well_activity_type': 'latest_well_activity_type_code', + 'work_start_date': 'last_activity_start_date', + 'work_end_date': 'last_activity_end_date' + } + + # Get mapped annoation name + related_order = related_order_mapping.get(order_field, '') + + # if we're descending, then add the negative sign prefix + if order_value.startswith('-'): + related_order = f'-{related_order}' + + # print(f"ORDER VALUES: {order_value}, Descending: {order_value.startswith('-')}, Field: {order_field}") + + # Apply sorting field annotations + queryset = self.annotate_custom_fields(queryset, order_field) + + # Return ordered queryset + return queryset.order_by(related_order) + + + def annotate_custom_fields(self, queryset, field_name): + # Apply annotations for calculated fields if they are not already annotated + if field_name == 'aquifer_lithology' and not queryset.query.annotations.get('last_lithology_raw_data'): + queryset = queryset.annotate(last_lithology_raw_data=Subquery( + LithologyDescription.objects.filter( + well=OuterRef('pk') + ).order_by('-end').values('lithology_raw_data')[:1] + )) + + if field_name == 'diameter' and not queryset.query.annotations.get('last_casing_diameter'): + queryset = queryset.annotate(last_casing_diameter=Subquery( + Casing.objects.filter( + well=OuterRef('pk') + ).order_by('-end').values('diameter')[:1] + )) + + if field_name == 'well_activity_type' and not queryset.query.annotations.get('latest_well_activity_type_code'): + queryset = queryset.annotate(latest_well_activity_type_code=Subquery( + ActivitySubmission.objects.filter( + well=OuterRef('pk') + ).exclude( + well_activity_type__code="STAFF_EDIT" + ).order_by( + '-work_end_date' + ).values( + 'well_activity_type__code' + )[:1] + )) + + if field_name == 'work_start_date' and not queryset.query.annotations.get('last_activity_start_date'): + queryset = queryset.annotate(last_activity_start_date=Subquery( + ActivitySubmission.objects.filter( + well=OuterRef('pk') + ).order_by('-work_start_date').values('work_start_date')[:1] + )) + + if field_name == 'work_end_date' and not queryset.query.annotations.get('last_activity_end_date'): + queryset = queryset.annotate(last_activity_end_date=Subquery( + ActivitySubmission.objects.filter( + well=OuterRef('pk') + ).order_by('-work_end_date').values('work_end_date')[:1] + )) + + return queryset diff --git a/app/backend/wells/fixtures/qaqc_well_data.zip b/app/backend/wells/fixtures/qaqc_well_data.zip new file mode 100644 index 0000000000..f367c1931e Binary files /dev/null and b/app/backend/wells/fixtures/qaqc_well_data.zip differ diff --git a/app/backend/wells/fixtures/well_detail_fixture.json b/app/backend/wells/fixtures/well_detail_fixture.json index 751e2ee4ae..7b36e43ab2 100644 --- a/app/backend/wells/fixtures/well_detail_fixture.json +++ b/app/backend/wells/fixtures/well_detail_fixture.json @@ -114,5 +114,14 @@ "construction_start_date": null, "well_status": null, "filter_pack_thickness": null, - "well_yield": null}} + "well_yield": null, + "distance_to_pid": "123.45", + "geocode_distance": "543.21", + "score_address": "78.90", + "score_city": "56.78", + "cross_referenced": false, + "cross_referenced_date": "2023-02-08T17:06:47.229Z", + "cross_referenced_by": "DATA_LOAD_USER", + "natural_resource_region": "Northeast" + }} ] diff --git a/app/backend/wells/migrations/0147_auto_20240105_qaqc.py b/app/backend/wells/migrations/0147_auto_20240105_qaqc.py new file mode 100644 index 0000000000..e11adb0b45 --- /dev/null +++ b/app/backend/wells/migrations/0147_auto_20240105_qaqc.py @@ -0,0 +1,56 @@ +# Generated by Django 2.2.28 on 2024-01-05 02:20 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('wells', '0146_add_aquifer_parameters_to_wells_view'), + ] + + operations = [ + migrations.AddField( + model_name='well', + name='distance_to_pid', + field=models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True, verbose_name='Distance to PID'), + ), + migrations.AddField( + model_name='well', + name='geocode_distance', + field=models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True, verbose_name='Geocode Distance'), + ), + migrations.AddField( + model_name='well', + name='score_address', + field=models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True, verbose_name='Score for Address'), + ), + migrations.AddField( + model_name='well', + name='score_city', + field=models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True, verbose_name='Score for City'), + ), + migrations.AddField( + model_name='well', + name='cross_referenced', + field=models.BooleanField(default=False, verbose_name='Cross Referenced'), + ), + migrations.AddField( + model_name='well', + name='cross_referenced_date', + field=models.DateTimeField(null=True, default=None), + ), + migrations.AddField( + model_name='well', + name='cross_referenced_by', + field=models.CharField(null=True, blank=True, max_length=100), + ), + migrations.AddField( + model_name='well', + name='natural_resource_region', + field=models.CharField(null=True, blank=True, max_length=200), + ), + ] diff --git a/app/backend/wells/migrations/0148_auto_20240105_qaqc_data.py b/app/backend/wells/migrations/0148_auto_20240105_qaqc_data.py new file mode 100644 index 0000000000..5ab9ea1d34 --- /dev/null +++ b/app/backend/wells/migrations/0148_auto_20240105_qaqc_data.py @@ -0,0 +1,70 @@ +from django.db import migrations +import csv +import zipfile +import os + +def import_well_data(apps, schema_editor): + Well = apps.get_model('wells', 'Well') + well_count = Well.objects.count() + dev_threshold = 500 + + if well_count < dev_threshold: + print("Skipping qaqc data migration as it seems to be a non-production environment.") + return + + process_wells(Well, get_well_data()) + +def get_well_data(): + migration_dir = os.path.dirname(__file__) + with zipfile.ZipFile(os.path.join(migration_dir, '../fixtures/qaqc_well_data.zip'), 'r') as zip_file: + csv_filename = zip_file.namelist()[0] + with zip_file.open(csv_filename, 'r') as csvfile: + return csv.DictReader(csvfile.read().decode('utf-8').splitlines()) + +def process_wells(Well, reader): + batch_size = 1000 # Adjust batch size if there are memory issues + wells_to_update = [] + count = 0 + + for row in reader: + try: + well_instance = Well.objects.get(well_tag_number=row['well_tag_number']) + update_well_attributes(well_instance, row) + wells_to_update.append(well_instance) + count += 1 + + # Process in batches of batch_size + if count % batch_size == 0: + Well.objects.bulk_update(wells_to_update, ['geocode_distance', 'distance_to_pid', 'score_address', 'score_city', 'cross_referenced', 'natural_resource_region']) + wells_to_update = [] # Reset the list after updating + + except Well.DoesNotExist: + print(f"Well with tag number {row['well_tag_number']} not found.") + except ValueError as e: + print(f"Error processing well {row['well_tag_number']}: {e}") + + # Update any remaining wells in the list + if wells_to_update: + Well.objects.bulk_update(wells_to_update, ['geocode_distance', 'distance_to_pid', 'score_address', 'score_city', 'cross_referenced', 'natural_resource_region']) + +def update_well_attributes(well, row): + fields_to_update = ['distance_geocode', 'distance_to_matching_pid', 'score_address', 'score_city'] + for field in fields_to_update: + setattr(well, 'geocode_distance' if field == 'distance_geocode' else field, + float(row[field]) if row[field] else None) + + well.cross_referenced = row['xref_ind'] == 'True' + if well.cross_referenced: + well.cross_referenced_date = well.update_date + well.cross_referenced_by = well.update_user + well.natural_resource_region = row['nr_region_name'] if row['nr_region_name'] else None + +class Migration(migrations.Migration): + + dependencies = [ + ('wells', '0147_auto_20240105_qaqc'), + ] + + operations = [ + migrations.RunPython(import_well_data, reverse_code=migrations.RunPython.noop), + ] diff --git a/app/backend/wells/models.py b/app/backend/wells/models.py index ee00e7e598..3c9c2b0b1b 100644 --- a/app/backend/wells/models.py +++ b/app/backend/wells/models.py @@ -13,16 +13,14 @@ """ import uuid -import math import reversion from decimal import Decimal from django.core.validators import MinValueValidator from django.utils import timezone -from django.dispatch import receiver -from django.db.models.signals import pre_save + from django.contrib.gis.db import models -from django.contrib.gis.gdal import SpatialReference, CoordTransform + from gwells.models import AuditModel, ProvinceStateCode, ScreenIntakeMethodCode, ScreenMaterialCode,\ ScreenOpeningCode, ScreenBottomCode, ScreenTypeCode, ScreenAssemblyTypeCode, CodeTableModel,\ @@ -34,6 +32,7 @@ LithologyMoistureCode, SurficialMaterialCode) from gwells.db_comments.patch_fields import patch_fields + # from aquifers.models import Aquifer patch_fields() @@ -1148,6 +1147,31 @@ class Well(AuditModelStructure): recommended_pump_rate = models.DecimalField(max_digits=7, decimal_places=2, blank=True, null=True, verbose_name='Recommended pump rate', validators=[MinValueValidator(Decimal('0.00'))]) + # QaQc Fields for internal use + geocode_distance = models.DecimalField( + null=True, blank=True, max_digits=12, decimal_places=2, verbose_name='Geocode Distance', + db_comment='Distance calculated during geocoding process.') + distance_to_pid = models.DecimalField( + null=True, blank=True, max_digits=12, decimal_places=2, verbose_name='Distance to PID', + db_comment='Distance to the Property Identification Description.') + score_address = models.DecimalField( + null=True, blank=True, max_digits=7, decimal_places=2, verbose_name='Score for Address', + db_comment='Score representing the accuracy or confidence of the address geocoding.') + score_city = models.DecimalField( + null=True, blank=True, max_digits=7, decimal_places=2, verbose_name='Score for City', + db_comment='Score representing the accuracy or confidence of the city geocoding.') + cross_referenced = models.BooleanField( + default=False, verbose_name='Cross Referenced', + db_comment='Indicates if the record has been cross-referenced by an internal team member.') + cross_referenced_date = models.DateTimeField( + null=True, verbose_name='Cross Referenced Date', + db_comment='The date when a well was cross referenced by an internal team member.') + cross_referenced_by = models.CharField( + max_length=100, blank=True, null=True, + verbose_name="Internal team member who cross referenced well.") + natural_resource_region = models.CharField( + max_length=250, blank=True, null=True, verbose_name="Natural Resource Region", + db_comment='The Natural Resource Region the well is located within.') class Meta: db_table = 'well' @@ -1281,19 +1305,6 @@ def longitude(self): } -@receiver(pre_save, sender=Well) -def update_utm(sender, instance, **kwargs): - if instance.geom and (-180 < instance.geom.x < 180): # only update utm when geom is valid - utm_zone = math.floor((instance.geom.x + 180) / 6) + 1 - coord_transform = CoordTransform(SpatialReference(4326), SpatialReference(32600 + utm_zone)) - utm_point = instance.geom.transform(coord_transform, clone=True) - - instance.utm_zone_code = utm_zone - # We round to integers because easting/northing is only precise to 1m. The DB column is also an integer type. - instance.utm_easting = round(utm_point.x) - instance.utm_northing = round(utm_point.y) - - class CasingMaterialCode(CodeTableModel): """ The material used for casing a well, e.g., Cement, Plastic, Steel. diff --git a/app/backend/wells/renderers.py b/app/backend/wells/renderers.py index d972b01ad3..f48866d071 100644 --- a/app/backend/wells/renderers.py +++ b/app/backend/wells/renderers.py @@ -141,7 +141,24 @@ "artesian_conditions": "Artesian Conditions", "alternative_specs_submitted": "Alt specs submitted", "technical_report": "Technical Report", - "drinking_water_protection_area_ind": "Drinking Water Protection Area" + "drinking_water_protection_area_ind": "Drinking Water Protection Area", + "well_activity_type": "Work/Report Type", + "work_start_date": "Work Start Date", + "work_end_date": "Work End Date", + "create_user": "Created By", + "create_date": "Created Date", + "update_date": "Updated Date", + "update_user": "Updated By", + "natural_resource_region": "Natural Resource Region", + "comments": "Comments", + "internal_comments": "Internal Comments", + "cross_referenced": "Cross Referenced", + "cross_referenced_date": "Cross Referenced Date", + "cross_referenced_by": "Cross Referenced By", + "geocode_distance": "Geocode Distance", + "distance_to_pid": "Distance to Matching PID", + "score_address": "Score Address", + "score_city": "Score City" } diff --git a/app/backend/wells/serializers_v2.py b/app/backend/wells/serializers_v2.py index 812557621c..ee0acec3db 100644 --- a/app/backend/wells/serializers_v2.py +++ b/app/backend/wells/serializers_v2.py @@ -18,7 +18,7 @@ from django.contrib.gis.geos import Point from gwells.utils import isPointInsideBC -from wells.models import Well, DevelopmentMethodCode +from wells.models import Well, DevelopmentMethodCode, ActivitySubmission from aquifers.models import VerticalAquiferExtent, Aquifer from aquifers.serializers_v2 import AquiferDetailSerializerV2 @@ -29,6 +29,7 @@ ) from aquifers.serializers import HYDRAULIC_SUBTYPES +COMPANY_OF_PERSON_RESPONSIBLE_NAME_FIELD = 'company_of_person_responsible.name' logger = logging.getLogger(__name__) @@ -148,7 +149,7 @@ class WellListSerializerV2(serializers.ModelSerializer): company_of_person_responsible = serializers.ReadOnlyField( source='company_of_person_responsible.org_guid') company_of_person_responsible_name = serializers.ReadOnlyField( - source='company_of_person_responsible.name') + source=COMPANY_OF_PERSON_RESPONSIBLE_NAME_FIELD) person_responsible = serializers.ReadOnlyField( source='person_responsible.person_guid') person_responsible_name = serializers.ReadOnlyField(source='person_responsible.name') @@ -318,7 +319,7 @@ class WellExportSerializerV2(WellListSerializerV2): licenced_status = serializers.SlugRelatedField(read_only=True, slug_field='description') land_district = serializers.SlugRelatedField(read_only=True, slug_field='name') drilling_company = serializers.CharField(read_only=True, - source='company_of_person_responsible.name') + source=COMPANY_OF_PERSON_RESPONSIBLE_NAME_FIELD) ground_elevation_method = serializers.SlugRelatedField(read_only=True, slug_field='description') surface_seal_material = serializers.SlugRelatedField(read_only=True, slug_field='description') @@ -458,3 +459,171 @@ class WellDetailSerializer(WellDetailSerializerV1): class Meta(WellDetailSerializerV1.Meta): ref_name = "well_detail_v2" + + +WELL_ACTIVITY_CODE_CONSTRUCTION = 'CON' +WELL_ACTIVITY_CODE_DECOMMISSION = 'DEC' +WELL_ACTIVITY_CODE_ALTERATION = 'ALT' +WELL_ACTIVITY_CODE_STAFF_EDIT = 'STAFF_EDIT' + +class ActivitySubmissionMixin: + def get_last_activity(self, obj): + # Cache the last activity in the instance to avoid repeated queries. + if not hasattr(obj, '_last_activity'): + obj._last_activity = ActivitySubmission.objects.filter( + well=obj + ).exclude( + well_activity_type__code=WELL_ACTIVITY_CODE_STAFF_EDIT + ).order_by('-work_end_date').first() + return obj._last_activity + + def get_well_activity_type(self, obj): + last_activity = self.get_last_activity(obj) + return last_activity.well_activity_type.code if last_activity else None + + def get_work_start_date(self, obj): + activity_type = self.get_well_activity_type(obj) + if activity_type == WELL_ACTIVITY_CODE_CONSTRUCTION: + order_field = '-construction_start_date' + elif activity_type == WELL_ACTIVITY_CODE_ALTERATION: + order_field = '-alteration_start_date' + elif activity_type == WELL_ACTIVITY_CODE_DECOMMISSION: + order_field = '-decommission_start_date' + else: + order_field = '-work_start_date' # Default order field if none of the conditions are met + + filter_field = order_field.strip('-') + last_activity = ActivitySubmission.objects.filter( + well=obj, + **{f'{filter_field}__isnull': False} + ).order_by(order_field).first() + return getattr(last_activity, order_field.strip('-'), None) if last_activity else None + + def get_work_end_date(self, obj): + activity_type = self.get_well_activity_type(obj) + if activity_type == WELL_ACTIVITY_CODE_CONSTRUCTION: + order_field = '-construction_end_date' + elif activity_type == WELL_ACTIVITY_CODE_ALTERATION: + order_field = '-alteration_end_date' + elif activity_type == WELL_ACTIVITY_CODE_DECOMMISSION: + order_field = '-decommission_end_date' + else: + order_field = '-work_end_date' # Default order field if none of the conditions are met + + filter_field = order_field.strip('-') + last_activity = ActivitySubmission.objects.filter( + well=obj, + **{f'{filter_field}__isnull': False} + ).order_by(order_field).first() + return getattr(last_activity, order_field.strip('-'), None) if last_activity else None + + +class MislocatedWellsSerializer(ActivitySubmissionMixin, serializers.ModelSerializer): + company_of_person_responsible_name = serializers.ReadOnlyField( + source=COMPANY_OF_PERSON_RESPONSIBLE_NAME_FIELD) + + well_activity_type = serializers.SerializerMethodField() + work_start_date = serializers.SerializerMethodField() + work_end_date = serializers.SerializerMethodField() + + class Meta: + model = Well + fields = [ + 'well_tag_number', + 'geocode_distance', + 'distance_to_pid', + 'score_address', + 'score_city', + 'well_activity_type', + 'work_start_date', + 'work_end_date', + 'company_of_person_responsible_name', + 'natural_resource_region', + 'create_date', + 'create_user', + 'internal_comments' + ] + + +class CrossReferencingSerializer(ActivitySubmissionMixin, serializers.ModelSerializer): + well_activity_type = serializers.SerializerMethodField() + work_start_date = serializers.SerializerMethodField() + work_end_date = serializers.SerializerMethodField() + + class Meta: + model = Well + fields = [ + 'well_tag_number', + 'well_activity_type', + 'work_start_date', + 'work_end_date', + 'create_user', + 'create_date', + 'update_date', + 'update_user', + 'natural_resource_region', + 'comments', + 'internal_comments', + 'cross_referenced', + 'cross_referenced_date', + 'cross_referenced_by' + ] + + +class RecordComplianceSerializer(ActivitySubmissionMixin, serializers.ModelSerializer): + company_of_person_responsible_name = serializers.ReadOnlyField( + source=COMPANY_OF_PERSON_RESPONSIBLE_NAME_FIELD) + person_responsible_name = serializers.ReadOnlyField(source='person_responsible.name') + + # Serializer methods for the last ActivitySubmission's work types + well_activity_type = serializers.SerializerMethodField() + work_start_date = serializers.SerializerMethodField() + work_end_date = serializers.SerializerMethodField() + + # last_lithology_raw_data + aquifer_lithology = serializers.SerializerMethodField() + # Serializer method field for the last casing's diameter + diameter = serializers.SerializerMethodField() + # Expose well_subclass uuid to convert to string + well_subclass = serializers.SerializerMethodField() + + def get_well_subclass(self, obj): + # This method will convert the UUID to a string + return str(obj.well_subclass) if obj.well_subclass else None + + def get_aquifer_lithology(self, obj): + # Fetch the last LithologyDescription based on the sequence number + last_lithology = obj.lithologydescription_set.order_by('-end').first() + # Return the raw data if it exists, otherwise return None + return last_lithology.lithology_raw_data if last_lithology else None + + def get_diameter(self, obj): + # Fetch the last Casing based on the 'end' field + last_casing = obj.casing_set.order_by('-end').first() + # Return the diameter if it exists, otherwise return None + return last_casing.diameter if last_casing else None + + class Meta: + model = Well + fields = [ + 'well_tag_number', + 'identification_plate_number', + 'well_subclass', + 'well_class', + 'latitude', + 'longitude', + 'finished_well_depth', + 'diameter', + 'surface_seal_depth', + 'surface_seal_thickness', + 'aquifer_lithology', + 'well_activity_type', + 'work_start_date', + 'work_end_date', + 'person_responsible_name', + 'company_of_person_responsible_name', + 'create_date', + 'create_user', + 'natural_resource_region', + 'internal_comments' + ] diff --git a/app/backend/wells/signals.py b/app/backend/wells/signals.py new file mode 100644 index 0000000000..0925ddb72a --- /dev/null +++ b/app/backend/wells/signals.py @@ -0,0 +1,110 @@ +import math +from django.utils import timezone +from django.dispatch import receiver +from django.db.models.signals import pre_save +from django.contrib.gis.gdal import SpatialReference, CoordTransform +from wells.models import Well +from gwells.settings import TESTING +from wells.utils import calculate_geocode_distance, calculate_pid_distance_for_well, \ + calculate_score_address, calculate_score_city, calculate_natural_resource_region_for_well, \ + reverse_geocode + +@receiver(pre_save, sender=Well) +def update_utm(sender, instance, **kwargs): + if instance.geom and (-180 < instance.geom.x < 180): # only update utm when geom is valid + utm_zone = math.floor((instance.geom.x + 180) / 6) + 1 + coord_transform = CoordTransform(SpatialReference(4326), SpatialReference(32600 + utm_zone)) + utm_point = instance.geom.transform(coord_transform, clone=True) + + instance.utm_zone_code = utm_zone + # We round to integers because easting/northing is only precise to 1m. The DB column is also an integer type. + instance.utm_easting = round(utm_point.x) + instance.utm_northing = round(utm_point.y) + +if not TESTING: + @receiver(pre_save, sender=Well) + def update_well(sender, instance, **kwargs): + """ + Signal receiver that triggers before a Well instance is saved. + + For new Well instances, it calculates and sets various geographical and scoring fields. + For existing Well instances, it recalculates these fields if the geographical location (geom) has changed. + + Parameters: + sender (Model Class): The model class that sent the signal. Should always be the Well model. + instance (Well instance): The instance of Well being saved. + kwargs: Additional keyword arguments. Not used in this function. + """ + + def is_valid_geom(geom): + """ + Helper function to check if the geom attribute is valid. + A valid geom should be non-null and must have both latitude and longitude. + """ + return geom and hasattr(geom, 'x') and hasattr(geom, 'y') + + def contains_cross_reference_comment(comments): + """ + Helper function to check if comments contain any of the specified search terms + indicating a cross-reference. + """ + search_terms = ["x-ref'd", "x-ref", "cross-ref", "cross r", "cross-r", "ref'd", "referenced", "refd", "xref", "x-r", "x r"] + comments_lower = comments.lower() if comments is not None else '' + return any(term in comments_lower for term in search_terms) + + try: + if instance._state.adding and not instance.pk: + # Handling new instance creation + if is_valid_geom(instance.geom): + set_well_attributes(instance) + else: + # Handling updates to existing instances + original_instance = sender.objects.get(pk=instance.pk) + geom_changed = original_instance.geom != instance.geom + address_changed = original_instance.street_address != instance.street_address + city_changed = original_instance.city != instance.city + pid_changed = original_instance.legal_pid != instance.legal_pid + + if (geom_changed or address_changed or city_changed or pid_changed) and is_valid_geom(instance.geom): + set_well_attributes(instance) + + # If comments indicate a cross-reference, set cross-reference attributes + if instance.comments and contains_cross_reference_comment(instance.comments): + set_cross_reference_attributes(instance) + + except Exception as e: + print(f"Error in update_well for Well ID {instance.pk}: {str(e)}") + + +def set_cross_reference_attributes(instance): + """ + Sets cross-reference attributes for a Well instance + when a user has set the comment to include one of + the cross referenced values. + """ + if not instance.cross_referenced: # Only update if not already set + instance.cross_referenced = True + instance.cross_referenced_date = timezone.now() + instance.cross_referenced_by = instance.update_user + + +def set_well_attributes(instance): + """ + Set attributes for a Well instance based on its geographical location. + + Parameters: + instance (Well instance): The instance of Well being processed. + """ + # Calculate distance scores + instance.geocode_distance = calculate_geocode_distance(instance) + instance.distance_to_pid = calculate_pid_distance_for_well(instance) + + # Geocode point to address + geocoded_address = reverse_geocode(instance.longitude, instance.latitude) + + # Calculate address scores + instance.score_address = calculate_score_address(instance, geocoded_address) + instance.score_city = calculate_score_city(instance, geocoded_address) + + # Calculate natural resource region of well + instance.natural_resource_region = calculate_natural_resource_region_for_well(instance) \ No newline at end of file diff --git a/app/backend/wells/urls.py b/app/backend/wells/urls.py index 162cef1df5..0053f5dc5d 100644 --- a/app/backend/wells/urls.py +++ b/app/backend/wells/urls.py @@ -123,4 +123,24 @@ # get geocoder address url(api_path_prefix() + r'/wells/geocoder$', views.AddressGeocoder.as_view(), name='address-geocoder'), + + # QA/QC Endpoints + url(api_path_prefix() + r'/qaqc/crossreferencing$', + never_cache(views_v2.CrossReferencingListView.as_view()), name='qaqc-cross-referencing'), + + url(api_path_prefix() + r'/qaqc/mislocatedwells$', + never_cache(views_v2.MislocatedWellsListView.as_view()), name='qaqc-mislocated-wells'), + + url(api_path_prefix() + r'/qaqc/recordcompliance$', + never_cache(views_v2.RecordComplianceListView.as_view()), name='qaqc-record-compliance'), + + # Download URLs for QA/QC Endpoints + url(api_path_prefix() + r'/qaqc/crossreferencing/download$', + never_cache(views_v2.CrossReferencingDownloadView.as_view()), name='qaqc-cross-referencing-download'), + + url(api_path_prefix() + r'/qaqc/mislocatedwells/download$', + never_cache(views_v2.MislocatedWellsDownloadView.as_view()), name='qaqc-mislocated-wells-download'), + + url(api_path_prefix() + r'/qaqc/recordcompliance/download$', + never_cache(views_v2.RecordComplianceDownloadView.as_view()), name='qaqc-record-compliance-download'), ] diff --git a/app/backend/wells/utils.py b/app/backend/wells/utils.py new file mode 100644 index 0000000000..dfffaaf883 --- /dev/null +++ b/app/backend/wells/utils.py @@ -0,0 +1,267 @@ +import json +import requests +import geopandas as gpd +from time import sleep +from shapely.geometry import Point +from django.contrib.gis.geos import GEOSGeometry +from wells.constants import ADDRESS_COLUMNS, GEOCODER_ENDPOINT +from thefuzz import fuzz +from django.db.models import Case, When, Value, DateField, F +from wells.models import Well +from pyproj import Proj, transform + +WELL_STATUS_CODE_CONSTRUCTION = 'CONSTRUCTION' +WELL_STATUS_CODE_ALTERATION = 'ALTERATION' +WELL_STATUS_CODE_DECOMMISSION = 'DECOMMISSION' +EPSG_4326 = 'epsg:4326' +EPSG_3005 = 'epsg:3005' + +def calculate_pid_distance_for_well(well): + """ + Calculate the distance from a single well to the nearest parcel using a WFS query. + :param well: A well instance with latitude, longitude attributes + :return: Distance to the nearest parcel in meters + """ + # Define projections + proj_4326 = Proj(init=EPSG_4326) # WGS 84 + proj_3005 = Proj(init=EPSG_3005) # NAD83 / BC Albers, uses meters + + # Transform the well's point to NAD83 / BC Albers + x_3005, y_3005 = transform(proj_4326, proj_3005, well.longitude, well.latitude) + well_point_3005 = Point(x_3005, y_3005) + + # Define base URL and parameters for the WFS request + base_url = "https://openmaps.gov.bc.ca/geo/pub/wfs" + params = { + "service": "WFS", + "version": "2.0.0", + "request": "GetFeature", + "typeName": "WHSE_CADASTRE.PMBC_PARCEL_FABRIC_POLY_SVW", + "outputFormat": "json", + "srsName": "EPSG:3005", # Ensure the response is in the same projection as the well point + "CQL_FILTER": f"PID_NUMBER={well.legal_pid}" + } + + # Construct and make the request + response = requests.get(f"{base_url}?{'&'.join([f'{k}={v}' for k, v in params.items()])}") + if response.status_code != 200: + print("Error making request to WFS service.") + return None + + # Load response into GeoDataFrame, already in EPSG:3005 + data = response.json() + parcels_gdf = gpd.GeoDataFrame.from_features(data["features"], crs="EPSG:3005") + + if parcels_gdf.empty: + print("No parcels found for the specified PID.") + return None + + # Calculate distances in meters from the well to each parcel + parcels_gdf["distance"] = parcels_gdf.geometry.distance(well_point_3005) + + # Return the minimum distance + min_distance = parcels_gdf["distance"].min() + + return round(min_distance) + + +def calculate_natural_resource_region_for_well(well): + """ + Retrieve the natural resource region name that a well is within using a WFS query. + :param well: A well instance with latitude, longitude attributes + :return: Natural Resource Region name + """ + # convert between projections + proj_4326 = Proj(init=EPSG_4326) # WGS 84 + proj_3005 = Proj(init=EPSG_3005) # NAD83 / BC Albers + + # Transform the point + x_3005, y_3005 = transform(proj_4326, proj_3005, well.longitude, well.latitude) + + # Base URL for the WFS request + base_url = "https://openmaps.gov.bc.ca/geo/pub/wfs" + params = { + "service": "WFS", + "version": "2.0.0", + "request": "GetFeature", + "typeName": "WHSE_ADMIN_BOUNDARIES.ADM_NR_REGIONS_SPG", + "outputFormat": "json", + "srsName": "EPSG:4326", + "CQL_FILTER": f"CONTAINS(SHAPE, POINT({x_3005} {y_3005}))", + "propertyName": "REGION_NAME,ORG_UNIT_NAME" + } + + # Construct the request URL + request_url = f"{base_url}?{'&'.join([f'{k}={v}' for k, v in params.items()])}" + + # Make the request + response = requests.get(request_url) + if response.status_code != 200: + print("Error making request to WFS service.") + return None + + # Load response into GeoDataFrame + data = response.json() + regions_gdf = gpd.GeoDataFrame.from_features(data["features"]) + + if regions_gdf.empty: + print("No natural resource regions found near well location.") + return None + + # Assuming the well can only be in one region, return the name of the first region found + return regions_gdf.iloc[0]['ORG_UNIT_NAME'] + + +def geocode(options={}): + """ + Performs an HTTP request to the BC Physical Address Geocoder API, + returning a django.contrib.gis.geos.Point for the first result. Supports query + string parameters via the 'options' argument. Raises HTTPError for + communication issues and ValueError if no matching coordinate is found. + Example 'options': {"addressString": "101 main st.", "localityName": "Kelowna"}. + """ + url = "https://geocoder.api.gov.bc.ca/addresses.json" + try: + response = requests.get(url, params=options) + + # Check if response status is ok + if response.status_code == 200: + data = response.json() + first_feature = data.get("features", [])[0] if data.get("features") else None + + if first_feature: + geometry = first_feature.get("geometry", {}) + # Directly extract coordinates to create a shapely Point + coordinates = geometry.get("coordinates", []) + if coordinates: + # Note the order: GeoJSON specifies coordinates as [longitude, latitude] + shapely_point = Point(coordinates[0], coordinates[1]) + return shapely_point + else: + raise ValueError("Geometry coordinates not found.") + else: + raise ValueError("No matching coordinate found for the given address.") + else: + response.raise_for_status() # This will raise an HTTPError if the response was an error + except Exception as e: + print(f"Error during geocoding: {e}") + return None + + +def reverse_geocode( + x, + y, + distance_start=200, + distance_increment=200, + distance_max=2000, +): + """ + Provided a location as x/y coordinates (EPSG:4326), request an address + from BC Geocoder within given distance_start (metres) + + If no result is found, request using an expanding search radius in + distance_increment steps, until distance_max is reached. + + A dict with 'distance' = 99999 is returned if no result is found. + + """ + try: + result = False + distance = distance_start + # expand the search distance until we get a result or hit the max distance + while result is False and distance <= distance_max: + params = { + "point": str(x) + "," + str(y), + "apikey": 'fake_api_key', # api key not required to be valid + "outputFormat": "json", + "maxDistance": distance, + } + r = requests.get(GEOCODER_ENDPOINT, params=params) + + # pause for 2s per request if near limit of 1000 requests/min + if int(r.headers["RateLimit-Remaining"]) < 30: + sleep(2) + if r.status_code == 200: + result = True + else: + distance = distance + distance_increment + if r.status_code == 200: + address = r.json().get("properties", {}) + if address: # Check if address is not empty + address["distance"] = distance + return address + # If no address return we default to an empty result + empty_result = dict([(k, "") for k in ADDRESS_COLUMNS]) + empty_result["distance"] = 99999 + return empty_result + except Exception as e: + print("geocode error:", e) + + +def calculate_geocode_distance(well): + """ + Calculates the geodesic distance between a well's location and its geocoded address. + + :param well: An object that contains the well's address, city, longitude, and latitude. + :return: The distance in meters between the well's actual location and its geocoded address. + """ + # Prepare the geocode request options with the well's street address and city + options = {"addressString": well.street_address or '', "localityName": well.city or ''} + + # Check if both addressString and localityName are empty, return None if true + if not options["addressString"].strip() and not options["localityName"].strip(): + print("Both addressString and localityName are empty. Skipping geocode.") + return None + + # Geocode the address to get a point representation (assuming WKT format) + geocoded_point = geocode(options) + well_point = Point(well.longitude, well.latitude) + + # Initialize projections for WGS84 and UTM Zone 10N (example) + proj_wgs84 = Proj(init='EPSG:4326') + proj_utm = Proj(init='epsg:32610') + # Transform the geocoded point and the well's location from WGS84 to UTM coordinates + x1, y1 = transform(proj_wgs84, proj_utm, geocoded_point.x, geocoded_point.y) + x2, y2 = transform(proj_wgs84, proj_utm, well_point.x, well_point.y) + # Calculate the distance between the points in meters within the UTM projection + distance_meters = Point(x1, y1).distance(Point(x2, y2)) + + return round(distance_meters) + + +def calculate_score_address(well, geocoded_address): + """ + Calculates the similarity score between the well's address and the geocoded address. + + :param well: An object that contains the well's street address. + :param geocoded_address: A dictionary containing the full address as geocoded. + :return: A similarity score or None if geocoded_address is not provided. + """ + if not geocoded_address: + # Return None if there's no geocoded address to compare with + return None + # Ensure the well's address is lowercased, using an empty string if address is None + street_address_lower = well.street_address.lower() if well.street_address is not None else '' + # Safely get the lowercased full address from geocoded_address, default to an empty string + geocoded_address_lower = geocoded_address.get('fullAddress', '').lower() + # Calculate and return the fuzzy similarity score between the two addresses + return fuzz.token_set_ratio(street_address_lower, geocoded_address_lower) + + +def calculate_score_city(well, geocoded_address): + """ + Calculates the similarity score between the well's city and the geocoded city. + + :param well: An object that contains the well's city. + :param geocoded_address: A dictionary containing the city name as 'localityName'. + :return: A similarity score or None if geocoded_address is not provided. + """ + if not geocoded_address: + # Return None if there's no geocoded address to compare with + return None + # Ensure the well's city is lowercased, using an empty string if city is None + city_lower = well.city.lower() if well.city is not None else '' + # Safely get the lowercased locality name from geocoded_address, default to an empty string + locality_name_lower = geocoded_address.get('localityName', '').lower() + # Calculate and return the fuzzy similarity score between the two city names + return fuzz.token_set_ratio(city_lower, locality_name_lower) \ No newline at end of file diff --git a/app/backend/wells/views_v2.py b/app/backend/wells/views_v2.py index b5a32c66c2..015de06851 100644 --- a/app/backend/wells/views_v2.py +++ b/app/backend/wells/views_v2.py @@ -20,8 +20,8 @@ from django.contrib.gis.db.models.functions import Distance from django.contrib.gis.geos import GEOSException, GEOSGeometry from django.contrib.gis.gdal import GDALException -from django.db.models import FloatField -from django.db.models.functions import Cast +from django.db.models.functions import Cast, Lower +from django.db.models import FloatField, Q, Case, When, F, Value, DateField from rest_framework import status, filters from rest_framework.exceptions import PermissionDenied, NotFound, ValidationError @@ -36,9 +36,11 @@ WellListFilterBackend, WellListOrderingFilter, GeometryFilterBackend, - RadiusFilterBackend + RadiusFilterBackend, + WellQaQcFilterBackend ) -from wells.models import Well, WellAttachment +from wells.models import Well, WellAttachment, \ + WELL_STATUS_CODE_ALTERATION, WELL_STATUS_CODE_CONSTRUCTION, WELL_STATUS_CODE_DECOMMISSION from wells.serializers_v2 import ( WellLocationSerializerV2, WellVerticalAquiferExtentSerializerV2, @@ -47,7 +49,10 @@ WellExportSerializerV2, WellExportAdminSerializerV2, WellSubsurfaceSerializer, - WellDetailSerializer + WellDetailSerializer, + MislocatedWellsSerializer, + CrossReferencingSerializer, + RecordComplianceSerializer ) from wells.permissions import WellsEditOrReadOnly from wells.renderers import WellListCSVRenderer, WellListExcelRenderer @@ -573,3 +578,105 @@ class WellDetail(WellDetailV1): This view is open to all, and has no permissions. """ serializer_class = WellDetailSerializer + +# QaQc Views + +class MislocatedWellsListView(ListAPIView): + """ + API view to retrieve mislocated wells. + """ + serializer_class = MislocatedWellsSerializer + + swagger_schema = None + permission_classes = (WellsEditOrReadOnly,) + model = Well + pagination_class = APILimitOffsetPagination + + # Allow searching on name fields, names of related companies, etc. + filter_backends = (WellListOrderingFilter, WellQaQcFilterBackend, + filters.SearchFilter) + + ordering = ('well_tag_number',) + + def get_queryset(self): + """ + This view should return a list of all mislocated wells + for the currently authenticated user. + """ + queryset = Well.objects.all() + + return queryset + + +class RecordComplianceListView(ListAPIView): + serializer_class = RecordComplianceSerializer + + swagger_schema = None + permission_classes = (WellsEditOrReadOnly,) + model = Well + pagination_class = APILimitOffsetPagination + + # Allow searching on name fields, names of related companies, etc. + filter_backends = (WellListOrderingFilter, WellQaQcFilterBackend, + filters.SearchFilter) + ordering = ('well_tag_number',) + + def get_queryset(self): + queryset = Well.objects.all() + + return queryset + + +class CrossReferencingListView(ListAPIView): + serializer_class = CrossReferencingSerializer + + swagger_schema = None + permission_classes = (WellsEditOrReadOnly,) + model = Well + pagination_class = APILimitOffsetPagination + + # Allow searching on name fields, names of related companies, etc. + filter_backends = (WellListOrderingFilter, WellQaQcFilterBackend, + filters.SearchFilter) + ordering = ('well_tag_number',) + + def get_queryset(self): + """ + Optionally restricts the returned wells to those that have certain keywords like 'x-ref'd' or 'cross-ref' + in their internal_comments. + """ + queryset = Well.objects.filter(cross_referenced=True) + + return queryset + +# Download Views for QaQc + +class MislocatedWellsDownloadView(WellExportListAPIViewV2): + filter_backends = (WellListOrderingFilter, WellQaQcFilterBackend, filters.SearchFilter) + + def get_queryset(self): + return Well.objects.all() + + def get_serializer_class(self): + return MislocatedWellsSerializer + + +class RecordComplianceDownloadView(WellExportListAPIViewV2): + filter_backends = (WellListOrderingFilter, WellQaQcFilterBackend, filters.SearchFilter) + + def get_queryset(self): + return Well.objects.all() + + def get_serializer_class(self): + return RecordComplianceSerializer + + +class CrossReferencingDownloadView(WellExportListAPIViewV2): + filter_backends = (WellListOrderingFilter, WellQaQcFilterBackend, filters.SearchFilter) + + def get_queryset(self): + # Return wells that have been cross-referenced + return Well.objects.filter(cross_referenced=True) + + def get_serializer_class(self): + return CrossReferencingSerializer \ No newline at end of file diff --git a/app/frontend/package-lock.json b/app/frontend/package-lock.json index c4cc294dc8..a52f66c24b 100644 --- a/app/frontend/package-lock.json +++ b/app/frontend/package-lock.json @@ -4,6 +4,16 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@babel/code-frame": { "version": "7.21.4", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", @@ -19,56 +29,258 @@ "dev": true }, "@babel/core": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", - "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helpers": "^7.4.4", - "@babel/parser": "^7.4.5", - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.4.5", - "@babel/types": "^7.4.4", - "convert-source-map": "^1.1.0", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.11", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "dependencies": { + "@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true + }, + "@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "requires": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", + "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + } + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, + "caniuse-lite": { + "version": "1.0.30001576", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", + "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", + "dev": true + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "electron-to-chromium": { + "version": "1.4.630", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.630.tgz", + "integrity": "sha512-osHqhtjojpCsACVnuD11xO5g9xaCyw7Qqn/C2KParkMv42i8jrJJgx3g7mkHfpxwhy9MnOJr8+pKOdZ7qzgizg==", + "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 + }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } } } }, - "@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", - "dev": true, - "requires": { - "@babel/types": "^7.21.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, "@babel/helper-annotate-as-pure": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", @@ -102,9 +314,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -165,9 +377,9 @@ "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -337,17 +549,6 @@ "@babel/types": "^7.20.5" } }, - "@babel/helpers": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", - "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", - "dev": true, - "requires": { - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, "@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", @@ -743,9 +944,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -894,31 +1095,144 @@ } }, "@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", - "debug": "^4.1.0", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "dependencies": { + "@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "requires": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "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 } } }, @@ -1118,247 +1432,77 @@ "integrity": "sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI=" }, "@mapbox/polyline": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@mapbox/polyline/-/polyline-1.2.0.tgz", - "integrity": "sha512-sIIi9clVZiTmXYqbXpSAoG+ZLsvQn7j9FJLqiNOG85KnXN8tz11MEhuW2M7NDEDIKi4hIMaSI1CKwH8oLuVxPQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@mapbox/polyline/-/polyline-1.2.1.tgz", + "integrity": "sha512-sn0V18O3OzW4RCcPoUIVDWvEGQaBNH9a0y5lgqrf5hUycyw1CzrhEoxV5irzrMNXKCkw1xRsZXcaVbsVZggHXA==", + "requires": { + "meow": "^9.0.0" + } + }, + "@mapbox/tiny-sdf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.1.1.tgz", + "integrity": "sha512-Ihn1nZcGIswJ5XGbgFAvVumOgWpvIjBX9jiRlIl46uQG9vJOF51ViBYHF95rEZupuyQbEmhLaDPLQlU7fUTsBg==" + }, + "@mapbox/unitbezier": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", + "integrity": "sha1-FWUb1VOme4WB+zmIEMmK2Go0Uk4=" + }, + "@mapbox/vector-tile": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", + "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "requires": { + "@mapbox/point-geometry": "~0.1.0" + } + }, + "@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==" + }, + "@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 + }, + "@nuxt/opencollective": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.3.3.tgz", + "integrity": "sha512-6IKCd+gP0HliixqZT/p8nW3tucD6Sv/u/eR2A9X4rxT/6hXlMzA4GZQzq4d2qnBAwSwGpmKyzkyTjNjrhaA25A==", "requires": { - "meow": "^6.1.1" + "chalk": "^4.1.0", + "consola": "^2.15.0", + "node-fetch": "^2.6.7" }, "dependencies": { - "camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" + "color-convert": "^2.0.1" } }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==" - }, - "meow": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz", - "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==", - "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "^4.0.2", - "normalize-package-data": "^2.5.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "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==", - "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==" - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "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==" - }, - "quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==" - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "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==" - } - } - }, - "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==", - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "dependencies": { - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" - } - } - }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "requires": { - "min-indent": "^1.0.0" - } - }, - "trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==" - }, - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==" - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "@mapbox/tiny-sdf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.1.1.tgz", - "integrity": "sha512-Ihn1nZcGIswJ5XGbgFAvVumOgWpvIjBX9jiRlIl46uQG9vJOF51ViBYHF95rEZupuyQbEmhLaDPLQlU7fUTsBg==" - }, - "@mapbox/unitbezier": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", - "integrity": "sha1-FWUb1VOme4WB+zmIEMmK2Go0Uk4=" - }, - "@mapbox/vector-tile": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", - "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", - "requires": { - "@mapbox/point-geometry": "~0.1.0" - } - }, - "@mapbox/whoots-js": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", - "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==" - }, - "@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 - }, - "@nuxt/opencollective": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.3.3.tgz", - "integrity": "sha512-6IKCd+gP0HliixqZT/p8nW3tucD6Sv/u/eR2A9X4rxT/6hXlMzA4GZQzq4d2qnBAwSwGpmKyzkyTjNjrhaA25A==", - "requires": { - "chalk": "^4.1.0", - "consola": "^2.15.0", - "node-fetch": "^2.6.7" - }, - "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.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "color-convert": { @@ -2070,12 +2214,20 @@ "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "dependencies": { + "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 + } } }, "default-gateway": { @@ -2212,9 +2364,9 @@ } }, "semver": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.0.tgz", - "integrity": "sha512-kCqEOOHoBcFs/2Ccuk4Xarm/KiWRSLEX9CAZF8xkJ6ZPlIoTZ8V5f7J16vYLJqDbR7KrxTJpR2lqjIEm2Qx9cQ==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true }, "shebang-command": { @@ -2298,9 +2450,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -2381,262 +2533,75 @@ "integrity": "sha512-Xn/+vdm9CjuC9p3Ae+lTClNutrVhsXpzxvoTXXtoys6kVRX9FkueSUAqSWAyZntmVLlR4DosBV4pH8y5Z/HbUw==", "dev": true }, - "@webassemblyjs/ast": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz", - "integrity": "sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA==", - "dev": true, - "requires": { - "@webassemblyjs/helper-module-context": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/wast-parser": "1.7.11" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz", - "integrity": "sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg==", + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", "dev": true }, - "@webassemblyjs/helper-api-error": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz", - "integrity": "sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg==", + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", "dev": true }, - "@webassemblyjs/helper-buffer": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz", - "integrity": "sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w==", + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, - "@webassemblyjs/helper-code-frame": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz", - "integrity": "sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw==", + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "requires": { - "@webassemblyjs/wast-printer": "1.7.11" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, - "@webassemblyjs/helper-fsm": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz", - "integrity": "sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A==", - "dev": true - }, - "@webassemblyjs/helper-module-context": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz", - "integrity": "sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg==", - "dev": true - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz", - "integrity": "sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ==", + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", "dev": true }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz", - "integrity": "sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q==", + "acorn-globals": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz", + "integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-buffer": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/wasm-gen": "1.7.11" + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + } } }, - "@webassemblyjs/ieee754": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz", - "integrity": "sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==", + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, + "optional": true, "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.11.tgz", - "integrity": "sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.1" - } - }, - "@webassemblyjs/utf8": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.11.tgz", - "integrity": "sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz", - "integrity": "sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-buffer": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/helper-wasm-section": "1.7.11", - "@webassemblyjs/wasm-gen": "1.7.11", - "@webassemblyjs/wasm-opt": "1.7.11", - "@webassemblyjs/wasm-parser": "1.7.11", - "@webassemblyjs/wast-printer": "1.7.11" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz", - "integrity": "sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/ieee754": "1.7.11", - "@webassemblyjs/leb128": "1.7.11", - "@webassemblyjs/utf8": "1.7.11" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz", - "integrity": "sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-buffer": "1.7.11", - "@webassemblyjs/wasm-gen": "1.7.11", - "@webassemblyjs/wasm-parser": "1.7.11" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz", - "integrity": "sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-api-error": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/ieee754": "1.7.11", - "@webassemblyjs/leb128": "1.7.11", - "@webassemblyjs/utf8": "1.7.11" - } - }, - "@webassemblyjs/wast-parser": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz", - "integrity": "sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/floating-point-hex-parser": "1.7.11", - "@webassemblyjs/helper-api-error": "1.7.11", - "@webassemblyjs/helper-code-frame": "1.7.11", - "@webassemblyjs/helper-fsm": "1.7.11", - "@xtuc/long": "4.2.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz", - "integrity": "sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/wast-parser": "1.7.11", - "@xtuc/long": "4.2.1" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz", - "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==", - "dev": true - }, - "abab": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", - "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, - "acorn-dynamic-import": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", - "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", - "dev": true, - "requires": { - "acorn": "^5.0.0" - } - }, - "acorn-globals": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz", - "integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==", - "dev": true, - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true - } - } - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "optional": true, - "requires": { - "acorn": "^3.0.4" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true, - "optional": true - } + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true, + "optional": true + } } }, "acorn-walk": { @@ -2684,7 +2649,7 @@ "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", "dev": true }, "ansi-colors": { @@ -2768,9 +2733,9 @@ "dev": true }, "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "dev": true, "requires": { "delegates": "^1.0.0", @@ -2813,7 +2778,7 @@ "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=", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", "dev": true }, "array-flatten": { @@ -2944,7 +2909,7 @@ "async-foreach": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", - "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "integrity": "sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA==", "dev": true }, "async-limiter": { @@ -3218,9 +3183,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -3588,7 +3553,7 @@ "block-stream": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "integrity": "sha512-OorbnJVPII4DuUKbjARAe8u8EfqOmkEEaSFIyoQ7OjTHn6kafxWl0wLgoZ2rXaYd7MyLcDaU4TmhfxtwgcccMQ==", "dev": true, "requires": { "inherits": "~2.0.0" @@ -3824,18 +3789,94 @@ } }, "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", "dev": true, "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.4", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" + }, + "dependencies": { + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.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 + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } } }, "browserify-zlib": { @@ -4099,20 +4140,24 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" }, "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==" + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==" } } }, @@ -4173,9 +4218,9 @@ "optional": true }, "chart.js": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.8.0.tgz", - "integrity": "sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", + "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", "requires": { "chartjs-color": "^2.1.0", "moment": "^2.10.2" @@ -4222,6 +4267,19 @@ "path-is-absolute": "^1.0.0", "readdirp": "^2.2.1", "upath": "^1.1.1" + }, + "dependencies": { + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + } } }, "chownr": { @@ -4312,177 +4370,172 @@ } }, "cli-highlight": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.1.tgz", - "integrity": "sha512-0y0VlNmdD99GXZHYnvrQcmHxP8Bi6T00qucGgBgGv4kJ0RyDthNnnFPupHV7PYv/OXSVk+azFbOeaW6+vGmx9A==", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", "dev": true, "requires": { - "chalk": "^2.3.0", - "highlight.js": "^9.6.0", + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", "mz": "^2.4.0", - "parse5": "^4.0.0", - "yargs": "^13.0.0" + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" }, "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "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==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "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 + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "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 }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "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 + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "invert-kv": "^2.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, - "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" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, - "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 - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" + "ansi-regex": "^5.0.1" } }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "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==", "dev": true, "requires": { - "p-try": "^2.0.0" + "has-flag": "^4.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==", + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.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 - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "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" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, "yargs": { - "version": "13.2.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", - "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.0" + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } }, "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } }, @@ -4543,26 +4596,14 @@ "dev": true }, "clone-deep": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", - "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, "requires": { - "for-own": "^1.0.0", "is-plain-object": "^2.0.4", - "kind-of": "^6.0.0", - "shallow-clone": "^1.0.0" - }, - "dependencies": { - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - } + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" } }, "clone-response": { @@ -4794,7 +4835,7 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "dev": true }, "consolidate": { @@ -5388,7 +5429,7 @@ "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", "dev": true, "requires": { "array-find-index": "^1.0.1" @@ -5652,7 +5693,7 @@ "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, "depd": { @@ -5989,17 +6030,6 @@ "once": "^1.4.0" } }, - "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - } - }, "entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", @@ -6203,12 +6233,20 @@ "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "dependencies": { + "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 + } } }, "doctrine": { @@ -6651,12 +6689,20 @@ "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "dependencies": { + "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 + } } }, "espree": { @@ -7400,9 +7446,9 @@ } }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==" }, "for-each": { "version": "0.3.3", @@ -7506,645 +7552,104 @@ "dev": true }, "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "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 + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "fuzzy": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz", + "integrity": "sha1-THbsL/CsGjap3M+aAN+GIweNTtg=" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", "dev": true, - "optional": true, "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" }, "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true }, - "balanced-match": { + "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, - "optional": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "number-is-nan": "^1.0.0" } }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { + "string-width": { "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, - "optional": true, "requires": { - "ms": "^2.1.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": 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" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": 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", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "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 - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "fuzzy": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz", - "integrity": "sha1-THbsL/CsGjap3M+aAN+GIweNTtg=" - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -8161,6 +7666,12 @@ "globule": "^1.0.0" } }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, "geojson-vt": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", @@ -8186,7 +7697,7 @@ "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", "dev": true }, "get-stream": { @@ -8356,20 +7867,20 @@ } }, "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", "dev": true, "requires": { "glob": "~7.1.1", - "lodash": "~4.17.10", + "lodash": "^4.17.21", "minimatch": "~3.0.2" }, "dependencies": { "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -8553,7 +8064,7 @@ "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, "has-value": { @@ -8626,12 +8137,6 @@ "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", "dev": true }, - "highlight.js": { - "version": "9.18.5", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.5.tgz", - "integrity": "sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==", - "dev": true - }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -8662,7 +8167,8 @@ "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true }, "hpack.js": { "version": "2.1.6", @@ -9099,19 +8605,15 @@ "dev": true }, "in-publish": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", - "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==", "dev": true }, "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" }, "indexes-of": { "version": "1.0.1", @@ -9119,12 +8621,6 @@ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true - }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -9224,12 +8720,6 @@ "loose-envify": "^1.0.0" } }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true - }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -11108,15 +10598,6 @@ "launch-editor": "^2.2.1" } }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, "left-pad": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", @@ -11306,12 +10787,6 @@ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, - "lodash.tail": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", - "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", - "dev": true - }, "lodash.transform": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.transform/-/lodash.transform-4.6.0.tgz", @@ -11351,7 +10826,7 @@ "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "integrity": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", "dev": true, "requires": { "currently-unhandled": "^0.4.1", @@ -11461,99 +10936,253 @@ "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.0.tgz", "integrity": "sha512-73l/qJQgj/T/zO1JXVfuVvvKDgikD/7D/rHAD28S9BG1OTstgmftrmqfCx4U+zQAmtsB6HcDA3a7ymdnJZAQgg==", "requires": { - "concat-stream": "~2.0.0", - "minimist": "^1.2.5" + "concat-stream": "~2.0.0", + "minimist": "^1.2.5" + } + }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "requires": { + "lru-cache": "^6.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==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "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==", + "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==" + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "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==" + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "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": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "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==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + }, + "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==" + } } }, - "concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "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==", "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } } }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "lru-cache": "^6.0.0" } + }, + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" } } }, - "math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", - "dev": true - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" - } - }, "merge": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", @@ -11799,24 +11428,6 @@ } } }, - "mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", - "dev": true, - "requires": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "dependencies": { - "for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", - "dev": true - } - } - }, "mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -12040,7 +11651,7 @@ "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "dev": true, "requires": { "abbrev": "1" @@ -12049,7 +11660,7 @@ "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "integrity": "sha512-mfmm3/H9+67MCVix1h+IXTpDwL6710LyHuk7+cWC9T1mE0qz4iHhh6r4hU2wrIT9iTsAAC2XQRvfblL028cpLw==", "dev": true } } @@ -12071,45 +11682,6 @@ "js-queue": "2.0.2" } }, - "node-libs-browser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", - "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "0.0.4" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, "node-notifier": { "version": "5.4.5", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.5.tgz", @@ -12157,19 +11729,35 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", "dev": true }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + } + }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -12182,13 +11770,22 @@ "cross-spawn": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", - "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "integrity": "sha512-eZ+m1WNhSZutOa/uRblAc9Ut5MQfukFrFMtPSm3bZCA888NmMd5AWXWdgRZ80zd+pTk1P2JrGjg9pUPTvl2PWQ==", "dev": true, "requires": { "lru-cache": "^4.0.1", "which": "^1.2.9" } }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -12199,25 +11796,68 @@ "yallist": "^2.1.2" } }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" } }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", "dev": true }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "dev": true } } @@ -12236,6 +11876,7 @@ "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", @@ -12518,88 +12159,27 @@ "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", "dev": true, - "requires": { - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-spinners": "^2.0.0", - "log-symbols": "^2.2.0", - "strip-ansi": "^5.2.0", - "wcwidth": "^1.0.1" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.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" - } - }, - "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" - } - }, - "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 - }, - "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" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" } }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -12784,6 +12364,23 @@ "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", "dev": true }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + } + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -12796,12 +12393,6 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, - "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", - "dev": true - }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", @@ -14002,22 +13593,20 @@ } }, "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" }, "dependencies": { "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "requires": { - "get-stdin": "^4.0.1" + "min-indent": "^1.0.0" } } } @@ -14549,6 +14138,19 @@ "minimist": "^1.1.1", "walker": "~1.0.5", "watch": "~0.18.0" + }, + "dependencies": { + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + } } }, "sass-graph": { @@ -14682,23 +14284,22 @@ } }, "sass-loader": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", - "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz", + "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==", "dev": true, "requires": { - "clone-deep": "^2.0.1", + "clone-deep": "^4.0.1", "loader-utils": "^1.0.1", - "lodash.tail": "^4.1.1", "neo-async": "^2.5.0", - "pify": "^3.0.0", - "semver": "^5.5.0" + "pify": "^4.0.1", + "semver": "^6.3.0" }, "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -14709,20 +14310,10 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, - "schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - } - }, "scss-tokenizer": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", - "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "integrity": "sha512-dYE8LhncfBUar6POCxMTm0Ln+erjeczqEvCJib5/7XNkdw1FkUGgwMPY360FY0FgPWQxHWCx29Jl3oejyGLM9Q==", "dev": true, "requires": { "js-base64": "^2.1.8", @@ -14747,7 +14338,8 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true }, "send": { "version": "0.18.0", @@ -14933,22 +14525,12 @@ } }, "shallow-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", - "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^5.0.0", - "mixin-object": "^2.0.1" - }, - "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 - } + "kind-of": "^6.0.2" } }, "shebang-command": { @@ -15240,7 +14822,7 @@ "source-map": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "integrity": "sha512-Y8nIfcb1s/7DcobUz1yOO1GSp7gyL+D9zLHDehT7iRESqGSxjJ448Sg7rvfgsRJCnKLdSl11uGf0s9X80cH0/A==", "dev": true, "requires": { "amdefine": ">=0.0.4" @@ -16244,10 +15826,9 @@ } }, "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==" }, "trim-right": { "version": "1.0.1", @@ -16694,15 +16275,6 @@ "extsprintf": "^1.2.0" } }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } - }, "vt-pbf": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.1.tgz", @@ -16967,13 +16539,6 @@ "to-regex-range": "^5.0.1" } }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, "glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -17058,35 +16623,312 @@ "dev": true }, "webpack": { - "version": "4.28.4", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.28.4.tgz", - "integrity": "sha512-NxjD61WsK/a3JIdwWjtIpimmvE6UrRi3yG54/74Hk9rwNj5FPkA4DJCf1z4ByDWLkvZhTZE+P3C/eh6UD5lDcw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-module-context": "1.7.11", - "@webassemblyjs/wasm-edit": "1.7.11", - "@webassemblyjs/wasm-parser": "1.7.11", - "acorn": "^5.6.2", - "acorn-dynamic-import": "^3.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz", + "integrity": "sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.4", - "tapable": "^1.1.0", - "terser-webpack-plugin": "^1.1.0", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dev": true, + "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==", + "dev": true + }, + "@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==", + "dev": true + }, + "@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==", + "dev": true + }, + "@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==", + "dev": true, + "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==", + "dev": true + }, + "@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==", + "dev": true, + "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==", + "dev": true + }, + "@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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "@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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@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==", + "dev": true + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + } + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + } } }, "webpack-bundle-analyzer": { @@ -17232,12 +17074,20 @@ } }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "dependencies": { + "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 + } } }, "find-up": { @@ -17323,9 +17173,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true }, "string-width": { @@ -17564,12 +17414,12 @@ } }, "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, "requires": { - "string-width": "^1.0.2 || 2" + "string-width": "^1.0.2 || 2 || 3 || 4" } }, "wkt-parser": { @@ -17666,9 +17516,9 @@ } }, "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", + "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", "dev": true, "requires": { "async-limiter": "~1.0.0" @@ -17698,16 +17548,16 @@ "dev": true }, "yargs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz", + "integrity": "sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==", "dev": true, "requires": { "cliui": "^4.0.0", "decamelize": "^1.1.1", "find-up": "^2.1.0", "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", + "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", @@ -17717,6 +17567,49 @@ "yargs-parser": "^9.0.2" }, "dependencies": { + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "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 + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, "y18n": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", diff --git a/app/frontend/src/common/components/Header.vue b/app/frontend/src/common/components/Header.vue index 79a7872135..764174ff98 100644 --- a/app/frontend/src/common/components/Header.vue +++ b/app/frontend/src/common/components/Header.vue @@ -44,6 +44,7 @@ Registry Search Submit Report Bulk Upload + QA/QC Dashboard Admin Groundwater Information @@ -89,6 +90,7 @@ export default { admin: adminMeta ? adminMeta.content === 'true' : false, aquifers: this.hasConfig && this.config.enable_aquifers_search === true, surveys: this.hasConfig && this.userRoles.surveys.edit === true, + qaqc: this.hasConfig && this.userRoles.submissions.edit === true, bulk } } diff --git a/app/frontend/src/qaqc/components/QaQcExports.vue b/app/frontend/src/qaqc/components/QaQcExports.vue new file mode 100644 index 0000000000..91754c3b49 --- /dev/null +++ b/app/frontend/src/qaqc/components/QaQcExports.vue @@ -0,0 +1,159 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + + + + \ No newline at end of file diff --git a/app/frontend/src/qaqc/components/QaQcFilters.vue b/app/frontend/src/qaqc/components/QaQcFilters.vue new file mode 100644 index 0000000000..d1a2542eee --- /dev/null +++ b/app/frontend/src/qaqc/components/QaQcFilters.vue @@ -0,0 +1,248 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + + + + + diff --git a/app/frontend/src/qaqc/components/QaQcTable.vue b/app/frontend/src/qaqc/components/QaQcTable.vue new file mode 100644 index 0000000000..1f72cbe243 --- /dev/null +++ b/app/frontend/src/qaqc/components/QaQcTable.vue @@ -0,0 +1,523 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + + + + + diff --git a/app/frontend/src/qaqc/store/actions.types.js b/app/frontend/src/qaqc/store/actions.types.js new file mode 100644 index 0000000000..a670ce3a5f --- /dev/null +++ b/app/frontend/src/qaqc/store/actions.types.js @@ -0,0 +1,16 @@ +/** + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +export const QAQC_SEARCH = 'QAQC_SEARCH' +export const RESET_QAQC_SEARCH = 'RESET_QAQC_SEARCH' +export const RESET_QAQC_DATA = 'RESET_QAQC_DATA' +export const FETCH_QAQC_WELL_DOWNLOAD_LINKS = 'FETCH_QAQC_WELL_DOWNLOAD_LINKS' +export const SET_QAQC_SELECTED_TAB_ACTION = 'SET_QAQC_SELECTED_TAB_ACTION' diff --git a/app/frontend/src/qaqc/store/index.js b/app/frontend/src/qaqc/store/index.js new file mode 100644 index 0000000000..9c9a7e0e88 --- /dev/null +++ b/app/frontend/src/qaqc/store/index.js @@ -0,0 +1,330 @@ +/** + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +import Vue from 'vue' +import Vuex from 'vuex' +import axios from 'axios' +import ApiService from '@/common/services/ApiService.js' + +import { + QAQC_SEARCH, + RESET_QAQC_SEARCH, + FETCH_QAQC_WELL_DOWNLOAD_LINKS, + SET_QAQC_SELECTED_TAB_ACTION +} from './actions.types.js' +import { + SET_QAQC_ERROR, + SET_QAQC_LAST_SEARCH_TRIGGER, + SET_QAQC_PENDING_SEARCH, + SET_QAQC_HAS_SEARCHED, + SET_QAQC_SEARCH_BOUNDS, + SET_QAQC_LIMIT, + SET_QAQC_OFFSET, + SET_QAQC_ORDERING, + SET_QAQC_ERRORS, + SET_QAQC_PARAMS, + SET_QAQC_RESULT_COLUMNS, + SET_QAQC_RESULT_COUNT, + SET_QAQC_RESULT_FILTERS, + SET_QAQC_RESULTS, + SET_QAQC_SELECTED_TAB +} from './mutations.types.js' + +Vue.use(Vuex) + +const cleanParams = (payload) => { + // Clear any null or empty string values, to keep URLs clean. + return Object.entries(payload).filter(([key, value]) => { + return !(value === undefined || value === '' || value === null) + }).reduce((cleanedParams, [key, value]) => { + cleanedParams[key] = value + return cleanedParams + }, {}) +} + +function buildSearchParams (state) { + const params = { ...state.qaqcParams } + + if (Object.entries(state.qaqcResultFilters).length > 0) { + params['filter_group'] = JSON.stringify(state.qaqcResultFilters) + } + + return params +} + +export const RECORD_COMPLIANCE_COLUMNS = [ + 'wellTagNumber', + 'identificationPlateNumber', + 'wellClass', + 'wellSubclass', + 'latitudeNull', + 'longitudeNull', + 'finishedWellDepthNull', + 'diameterNull', + 'surfaceSealDepthNull', + 'surfaceSealThicknessNull', + 'aquiferLithologyNull', + 'wellActivityType', + 'workStartDateNull', + 'workEndDateNull', + 'personResponsible', + 'orgResponsible', + 'naturalResourceRegion', + 'createDate', + 'createUser', + 'internalComments' +] + +export const MISLOCATED_WELLS_COLUMNS = [ + 'wellTagNumber', + 'geocodeDistance', + 'distanceToPid', + 'scoreAddress', + 'scoreCity', + 'wellActivityType', + 'workStartDateNull', + 'workEndDateNull', + 'orgResponsible', + 'naturalResourceRegion', + 'createDate', + 'createUser', + 'internalComments' +] + +export const CROSS_REFERENCING_COLUMNS = [ + 'wellTagNumber', + 'naturalResourceRegion', + 'createUser', + 'createDate', + 'updateUser', + 'updateDate', + 'crossReferencedDate', + 'crossReferencedBy', + 'comments', + 'internalComments' +] + +const DEFAULT_ORDERING = '-well_tag_number' +const DEFAULT_LIMIT = 10 + +const wellsStore = { + state: { + error: null, + lastSearchTrigger: null, + qaqcPendingSearch: null, + qaqcHasSearched: false, + qaqcBounds: {}, + qaqcErrors: {}, + qaqcLimit: DEFAULT_LIMIT, + qaqcOffset: 0, + qaqcOrdering: DEFAULT_ORDERING, + qaqcParams: {}, + qaqcResultColumns: CROSS_REFERENCING_COLUMNS, + qaqcResultFilters: {}, + qaqcResults: null, + qaqcResultCount: 0, + downloads: null, + selectedTab: 0 + }, + mutations: { + [SET_QAQC_SELECTED_TAB] (state, payload) { + state.selectedTab = payload + }, + [SET_QAQC_ERROR] (state, payload) { + state.error = payload + }, + [SET_QAQC_LAST_SEARCH_TRIGGER] (state, payload) { + state.lastSearchTrigger = payload + }, + [SET_QAQC_PENDING_SEARCH] (state, payload) { + state.qaqcPendingSearch = payload + }, + [SET_QAQC_HAS_SEARCHED] (state, payload) { + state.qaqcHasSearched = payload + }, + [SET_QAQC_ERRORS] (state, payload) { + state.qaqcErrors = payload + }, + [SET_QAQC_LIMIT] (state, payload) { + if (!(payload === 10 || payload === 25 || payload === 50)) { + return + } + state.qaqcLimit = payload + }, + [SET_QAQC_OFFSET] (state, payload) { + state.qaqcOffset = payload + }, + [SET_QAQC_ORDERING] (state, payload) { + state.qaqcOrdering = payload + }, + [SET_QAQC_PARAMS] (state, payload) { + state.qaqcParams = cleanParams(payload) + }, + [SET_QAQC_RESULT_COLUMNS] (state, payload) { + state.qaqcResultColumns = payload + }, + [SET_QAQC_RESULT_FILTERS] (state, payload) { + state.qaqcResultFilters = cleanParams(payload) + }, + [SET_QAQC_RESULTS] (state, payload) { + state.qaqcResults = payload + }, + [SET_QAQC_RESULT_COUNT] (state, payload) { + state.qaqcResultCount = payload + } + }, + actions: { + [SET_QAQC_SELECTED_TAB_ACTION] ({ commit, dispatch }, tab) { + commit('SET_QAQC_SELECTED_TAB', tab) + // Determine which columns to use based on the selected tab + let columns = [] + switch (tab) { + case 0: + columns = RECORD_COMPLIANCE_COLUMNS + break + case 1: + columns = MISLOCATED_WELLS_COLUMNS + break + case 2: + columns = CROSS_REFERENCING_COLUMNS + break + default: + columns = [] // Default case or you can set a default column set + } + // Commit a mutation to set the qaqc result columns + commit('SET_QAQC_RESULT_COLUMNS', columns) + commit('SET_QAQC_RESULT_COLUMNS', columns) + dispatch('QAQC_SEARCH', {}) + }, + [FETCH_QAQC_WELL_DOWNLOAD_LINKS] ({ commit, state }) { + if (state.downloads === null) { + ApiService.query('wells/extracts').then((response) => { + state.downloads = response.data + }) + } + }, + [RESET_QAQC_SEARCH] ({ commit, state }) { + if (state.qaqcPendingSearch !== null) { + state.qaqcPendingSearch.cancel() + } + commit(SET_QAQC_HAS_SEARCHED, false) + commit(SET_QAQC_PENDING_SEARCH, null) + commit(SET_QAQC_SEARCH_BOUNDS, {}) + commit(SET_QAQC_ORDERING, DEFAULT_ORDERING) + commit(SET_QAQC_LIMIT, DEFAULT_LIMIT) + commit(SET_QAQC_OFFSET, 0) + commit(SET_QAQC_PARAMS, {}) + commit(SET_QAQC_ERRORS, {}) + commit(SET_QAQC_RESULTS, null) + commit(SET_QAQC_RESULT_COUNT, 0) + commit(SET_QAQC_RESULT_FILTERS, {}) + }, + [QAQC_SEARCH] ({ commit, state }, { constrain = null, trigger = null }) { + commit(SET_QAQC_LAST_SEARCH_TRIGGER, trigger) + commit(SET_QAQC_HAS_SEARCHED, true) + + if (state.qaqcPendingSearch !== null) { + state.qaqcPendingSearch.cancel() + } + + const cancelSource = axios.CancelToken.source() + commit(SET_QAQC_PENDING_SEARCH, cancelSource) + + const params = { + ...buildSearchParams(state), + ordering: state.qaqcOrdering, + limit: state.qaqcLimit, + offset: state.qaqcOffset + } + + // Modify the endpoint or parameters based on the selectedTab + let endpoint = 'qaqc' + if (state.selectedTab === 0) { + endpoint += '/recordcompliance' + } else if (state.selectedTab === 1) { + endpoint += '/mislocatedwells' + } else if (state.selectedTab === 2) { + endpoint += '/crossreferencing' + } + + ApiService.query(endpoint, params, { cancelToken: cancelSource.token }).then((response) => { + commit(SET_QAQC_ERRORS, {}) + commit(SET_QAQC_RESULTS, response.data.results) + commit(SET_QAQC_RESULT_COUNT, response.data.count) + }).catch((err) => { + // If the qaqc was cancelled, a new one is pending, so don't bother resetting. + if (axios.isCancel(err)) { + return + } + + if (err.response && err.response.data) { + commit(SET_QAQC_ERRORS, err.response.data) + } + commit(SET_QAQC_RESULTS, null) + commit(SET_QAQC_RESULT_COUNT, 0) + }).finally(() => { + commit(SET_QAQC_PENDING_SEARCH, null) + }) + } + }, + getters: { + qaqcHasSearched (state) { + return state.qaqcHasSearched + }, + qaqcPendingSearch (state) { + return state.qaqcPendingSearch + }, + qaqcInProgress (state) { + return Boolean(state.qaqcPendingSearch) + }, + qaqcBounds (state) { + return state.qaqcBounds + }, + qaqcErrors (state) { + return state.qaqcErrors + }, + qaqcLimit (state) { + return state.qaqcLimit + }, + qaqcOffset (state) { + return state.qaqcOffset + }, + qaqcOrdering (state) { + return state.qaqcOrdering + }, + qaqcParams (state) { + return state.qaqcParams + }, + qaqcResultColumns (state) { + return state.qaqcResultColumns + }, + qaqcResultFilters (state) { + return state.qaqcResultFilters + }, + qaqcResultCount (state) { + return state.qaqcResultCount + }, + qaqcResults (state) { + return state.qaqcResults + }, + qaqcWellFileDownloads (state) { + return state.downloads + }, + searchQueryParams (state) { + return buildSearchParams(state) + }, + qaqcSelectedTab (state) { + return state.selectedTab + } + } +} + +export default wellsStore diff --git a/app/frontend/src/qaqc/store/mutations.types.js b/app/frontend/src/qaqc/store/mutations.types.js new file mode 100644 index 0000000000..f1ce2255e7 --- /dev/null +++ b/app/frontend/src/qaqc/store/mutations.types.js @@ -0,0 +1,27 @@ +/** + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +export const SET_QAQC_ERROR = 'SET_QAQC_ERROR' +export const SET_QAQC_LAST_SEARCH_TRIGGER = 'SET_QAQC_LAST_SEARCH_TRIGGER' +export const SET_QAQC_PENDING_LOCATION_SEARCH = 'SET_QAQC_PENDING_LOCATION_SEARCH' +export const SET_QAQC_HAS_SEARCHED = 'SET_QAQC_HAS_SEARCHED' +export const SET_QAQC_PENDING_SEARCH = 'SET_QAQC_PENDING_SEARCH' +export const SET_QAQC_BOUNDS = 'SET_QAQC_BOUNDS' +export const SET_QAQC_ERRORS = 'SET_QAQC_ERRORS' +export const SET_QAQC_LIMIT = 'SET_QAQC_LIMIT' +export const SET_QAQC_OFFSET = 'SET_QAQC_OFFSET' +export const SET_QAQC_ORDERING = 'SET_QAQC_ORDERING' +export const SET_QAQC_PARAMS = 'SET_QAQC_PARAMS' +export const SET_QAQC_RESULT_COLUMNS = 'SET_QAQC_RESULT_COLUMNS' +export const SET_QAQC_RESULT_FILTERS = 'SET_QAQC_RESULT_FILTERS' +export const SET_QAQC_RESULTS = 'SET_QAQC_RESULTS' +export const SET_QAQC_RESULT_COUNT = 'SET_QAQC_RESULT_COUNT' +export const SET_QAQC_SELECTED_TAB = 'SET_QAQC_SELECTED_TAB' diff --git a/app/frontend/src/qaqc/store/triggers.types.js b/app/frontend/src/qaqc/store/triggers.types.js new file mode 100644 index 0000000000..1db736471c --- /dev/null +++ b/app/frontend/src/qaqc/store/triggers.types.js @@ -0,0 +1,21 @@ +/** + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +// the QUERY trigger means the search was triggered by a querystring in the URL +// e.g. the user bookmarked a search or shared a link. +export const QUERY_TRIGGER = 'QUERY_TRIGGER' + +// the search trigger means the basic or advanced search form was used to search for wells. +export const SEARCH_TRIGGER = 'SEARCH_TRIGGER' + +// the filter trigger means that the search was triggered via search result filters. +export const FILTER_TRIGGER = 'FILTER_TRIGGER' diff --git a/app/frontend/src/qaqc/views/QaQcDashboard.vue b/app/frontend/src/qaqc/views/QaQcDashboard.vue new file mode 100644 index 0000000000..2ecbe96806 --- /dev/null +++ b/app/frontend/src/qaqc/views/QaQcDashboard.vue @@ -0,0 +1,42 @@ + + + diff --git a/app/frontend/src/router.js b/app/frontend/src/router.js index 21313ee3b6..44aadc723c 100644 --- a/app/frontend/src/router.js +++ b/app/frontend/src/router.js @@ -40,6 +40,9 @@ import PageNotFound from '@/common/components/PageNotFound.vue' // Surveys import Surveys from '@/surveys/views/Surveys.vue' +// QaQc +import QaQcDashboard from '@/qaqc/views/QaQcDashboard.vue' + Vue.use(Router) const router = new Router({ @@ -229,6 +232,11 @@ const router = new Router({ app: 'surveys' } }, + { + path: '/qaqc', + name: 'qaqc', + component: QaQcDashboard + }, { path: '/search', redirect: '/' }, { path: '/', diff --git a/app/frontend/src/store/index.js b/app/frontend/src/store/index.js index a97a052e8e..0362b6c22b 100644 --- a/app/frontend/src/store/index.js +++ b/app/frontend/src/store/index.js @@ -7,6 +7,7 @@ import registriesStore from '@/registry/store/index.js' import submissionStore from '@/submissions/store/index.js' import aquiferStore from '@/aquifers/store/index.js' import wellsStore from '@/wells/store/index.js' +import qaqcStore from '@/qaqc/store/index.js' Vue.use(Vuex) @@ -18,6 +19,7 @@ export const store = new Vuex.Store({ registriesStore, submissionStore, aquiferStore, - wellsStore + wellsStore, + qaqcStore } }) diff --git a/app/frontend/src/wells/components/mixins/filters.js b/app/frontend/src/wells/components/mixins/filters.js index 266e2a0c32..1e76c505ef 100644 --- a/app/frontend/src/wells/components/mixins/filters.js +++ b/app/frontend/src/wells/components/mixins/filters.js @@ -145,6 +145,14 @@ const SEARCH_FIELDS = { type: 'number', sortable: true, }, + wellActivityType: { + param: 'well_activity_type', + label: 'Well Activity Type', + type: 'select', + textField: 'description', + valueField: 'code', + sortable: true, + }, wellClass: { param: 'well_class', label: 'Class of well', @@ -874,6 +882,105 @@ const SEARCH_FIELDS = { textField: 'description', valueField: 'well_disinfected_code', sortable: true, + }, + latitude: { param: 'latitude', label: 'Latitude', type: 'number' }, + longitude: { param: 'longitude', label: 'Longitude', type: 'number' }, + geocodeDistance: { + param: 'geocode_distance', + label: 'Geocode Distance', + type: 'range', + sortable: true, + }, + distanceToPid: { + param: 'distance_to_pid', + label: 'Distance to Matching PID', + type: 'range', + sortable: true, + }, + scoreAddress: { + param: 'score_address', + label: 'Score Address', + type: 'range', + sortable: true, + }, + scoreCity: { + param: 'score_city', + label: 'Score City', + type: 'range', + sortable: true, + }, + naturalResourceRegion: { + param: 'natural_resource_region', + label: 'Natural Resource Region', + type: 'select', + sortable: true, + }, + finishedWellDepthNull: { + param: 'finished_well_depth', + label: 'Finished well depth', + type: 'nullcheck' + }, + intendedWaterUseNull: { + param: 'intended_water_use', + label: 'Intended water use', + type: 'nullcheck' + }, + wellClassNull: { + param: 'well_class', + label: 'Class of well', + type: 'nullcheck' + }, + latitudeNull: { + param: 'latitude', + label: 'Latitude', + type: 'nullcheck' + }, + longitudeNull: { + param: 'longitude', + label: 'Longitude', + type: 'nullcheck' + }, + diameterNull: { + param: 'diameter', + label: 'Casing Diameter (inches)', + type: 'nullcheck' + }, + surfaceSealDepthNull: { + param: 'surface_seal_depth', + label: 'Seal Depth (feet)', + type: 'nullcheck' + }, + surfaceSealThicknessNull: { + param: 'surface_seal_thickness', + label: 'Seal Thickness (inches)', + type: 'nullcheck' + }, + aquiferLithologyNull: { + param: 'aquifer_lithology', + label: 'Lithology', + type: 'nullcheck' + }, + workStartDateNull: { + param: 'work_start_date', + label: 'Work Start Date', + type: 'nullcheck' + }, + workEndDateNull: { + param: 'work_end_date', + label: 'Work End Date', + type: 'nullcheck' + }, + crossReferencedBy: { + param: 'cross_referenced_by', + label: 'Cross Referenced By', + type: 'text', + sortable: true + }, + crossReferencedDate: { + param: 'cross_referenced_date', + label: 'Cross Referenced Date', + type: 'dateRange', + sortable: true } } @@ -963,11 +1070,14 @@ export default { surfaceSealMethod: this.codes.surface_seal_methods || [], waterQualityCharacteristics: this.codes.water_quality_characteristics || [], waterQualityColour: this.codes.water_quality_colours || [], + wellActivityType: this.codes.activity_types || [], wellClass: this.codes.well_classes || [], wellDisinfectedStatus: this.codes.well_disinfected_codes || [], wellStatus: this.codes.well_status_codes || [], wellSubclass: this.wellSubclassOptions, - yieldEstimationMethod: this.codes.yield_estimation_methods || [] + yieldEstimationMethod: this.codes.yield_estimation_methods || [], + naturalResourceRegion: ['Northeast', 'West Coast', 'South Coast', 'Omineca', + 'Skeena', 'Thompson-Okanagan', 'Cariboo', 'Kootenay'] } Object.keys(options).forEach(optionId => { diff --git a/app/scripts/qaqc/README.md b/app/scripts/qaqc/README.md new file mode 100644 index 0000000000..afa1e56a5c --- /dev/null +++ b/app/scripts/qaqc/README.md @@ -0,0 +1,107 @@ +# GWELLS Location Data QA + +This suite of scripts is designed to generate Quality Assurance and Quality Control (QAQC) data for all wells registered in the GWELLS system. The primary objective is to build a comprehensive dataset that highlights potential data inconsistencies or issues within existing well records, thereby enabling internal staff to more effectively locate and address these issues. + +## Acknowledgements + +These scripts have been repurposed and adapted from an existing repository: [smnorris/gwells_locationqa](https://github.com/smnorris/gwells_locationqa). + +## Installation/Requirements + +1. Create and activate a Python virtual environment: + + ``` + python -m venv venv + source venv/bin/activate # On Windows, use `venv\Scripts\activate` + ``` + +2. Install the required Python packages: + + ``` + pip install -r requirements.txt + ``` + +## Download ESA WorldCover 2020 + +The ESA WorldCover dataset is a crucial component for the script but requires separate downloading. To download and prepare the tiff tiles for British Columbia (BC), ensure you have `awscli` and `gdal` installed and available at the command line. Then, execute the provided bash script: + + ```bash + ./get_esa_worldcover_bc.sh + ``` + +This script is designed for Unix-based systems (`bash`). It can be modified for Windows with minimal changes. + +For more information on the ESA WorldCover dataset, visit: + +- [ESA WorldCover Website](https://esa-worldcover.org/en) +- [ESA WorldCover Dataset Details](https://esa-worldcover.s3.amazonaws.com/readme.html) + +## Usage + +The scripts should be run in the following order: + +1. **Data Download**: + + Download the required data to the `/data` folder (including GWELLS and PMBC parcel fabric datasets): + + ```python + python gwells_locationqa.py download + ``` + +2. **Reverse Geocoding**: + + Perform reverse-geocoding for all wells. This process has an optional API key and takes approximately 6 hours: + + ```python + python gwells_locationqa.py geocode + ``` + +3. **Quality Assurance (QA)**: + + Match well PIDs to PMBC, match addresses, and overlay with agricultural data sources: + + ```python + python gwells_locationqa.py qa + ``` + +4. **Data Extraction**: + + Run the `extract_data.py` script to extract specific columns from the generated `gwells_locationqa.csv` file. This step focuses on key data points for further analysis in GWELLS: + + ```python + python extract_data.py + ``` + + This script isolates and extracts essential columns such as `well_tag_number`, `distance_geocode`, `distance_to_matching_pid`, `score_address`, `score_city`, and `xref_ind`, saving the refined data into a new file named `extracted_wells_data.csv`. This file is used in a migration to populate the database with this information. + +## Output + +The output file generated is `gwells_locationqa.csv`, which includes all wells with latitude and longitude data. + +The additional columns added to the output file for QAQC purposes are as follows: + +| Column | Description | +| ---------------------------- | ------------- | +| nr_district_name | Natural Resource District | +| nr_region_name | Natural Resource Region | +| fullAddress | Geocoder result | +| streetAddress | Geocoder results parsed to match GWELLS address | +| civicNumber | Geocoder result | +| civicNumberSuffix | Geocoder result | +| streetName | Geocoder result | +| streetType | Geocoder result | +| isStreetTypePrefix | Geocoder result | +| streetDirection | Geocoder result | +| isStreetDirectionPrefix | Geocoder result | +| streetQualifier | Geocoder result | +| localityName | Geocoder result | +| distance_geocode | Distance from well to result of geocode | +| distance_to_matching_pid | Distance from well to BC Parcel Fabric polygon with matching PID | +| score_address | Token Set Ratio score for matching well's address to reverse geocoded address | +| score_location_description | Token Set Ratio score for matching well's location description to reverse geocoded full address | +| score_city | Token Set Ratio score for matching well's city to reverse geocoded locality | +| xref_ind | Indicates if specific strings found in comments column | +| alr_ind | Indicates if the well is within the ALR as defined by relevant datasets | +| btm_label | BTM Present Land Use Label at well location | +| esa_landclass | ESA WorldCover land class at well location | + diff --git a/app/scripts/qaqc/extract_data.py b/app/scripts/qaqc/extract_data.py new file mode 100644 index 0000000000..326e747c30 --- /dev/null +++ b/app/scripts/qaqc/extract_data.py @@ -0,0 +1,26 @@ +import pandas as pd + +def extract_columns_from_csv(file_path, output_file_path): + """ + Extracts specific columns from a CSV file and saves them into another CSV file. + + Parameters: + file_path (str): The path to the input CSV file. + output_file_path (str): The path to the output CSV file. + """ + # Read the CSV file + df = pd.read_csv(file_path) + + # Extract the required columns + extracted_df = df[['well_tag_number', 'distance_geocode', 'distance_to_matching_pid', + 'score_address', 'score_city', 'xref_ind', 'nr_region_name']] + + # Save the extracted data to a new CSV file + extracted_df.to_csv(output_file_path, index=False) + + print(f"Extracted data saved to {output_file_path}") + + +file_path = 'gwells_locationqa.csv' +output_file_path = 'qaqc_well_data.csv' # Output file path +extract_columns_from_csv(file_path, output_file_path) diff --git a/app/scripts/qaqc/get_esa_worldcover_bc.sh b/app/scripts/qaqc/get_esa_worldcover_bc.sh new file mode 100755 index 0000000000..b869ae9945 --- /dev/null +++ b/app/scripts/qaqc/get_esa_worldcover_bc.sh @@ -0,0 +1,40 @@ +#!/bin/bash +set -euxo pipefail + +# create data folder if not present +mkdir -p data + +# Download BC tiles of ESA world landcover from S3 bucket +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N54W123_Map.tif data/ESA_WorldCover_10m_2020_v100_N54W123_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N57W120_Map.tif data/ESA_WorldCover_10m_2020_v100_N57W120_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N51W126_Map.tif data/ESA_WorldCover_10m_2020_v100_N51W126_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N57W138_Map.tif data/ESA_WorldCover_10m_2020_v100_N57W138_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N54W132_Map.tif data/ESA_WorldCover_10m_2020_v100_N54W132_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N48W117_Map.tif data/ESA_WorldCover_10m_2020_v100_N48W117_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N57W141_Map.tif data/ESA_WorldCover_10m_2020_v100_N57W141_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N48W120_Map.tif data/ESA_WorldCover_10m_2020_v100_N48W120_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N51W135_Map.tif data/ESA_WorldCover_10m_2020_v100_N51W135_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N51W120_Map.tif data/ESA_WorldCover_10m_2020_v100_N51W120_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N48W132_Map.tif data/ESA_WorldCover_10m_2020_v100_N48W132_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N54W129_Map.tif data/ESA_WorldCover_10m_2020_v100_N54W129_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N54W135_Map.tif data/ESA_WorldCover_10m_2020_v100_N54W135_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N57W135_Map.tif data/ESA_WorldCover_10m_2020_v100_N57W135_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N57W129_Map.tif data/ESA_WorldCover_10m_2020_v100_N57W129_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N51W129_Map.tif data/ESA_WorldCover_10m_2020_v100_N51W129_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N48W129_Map.tif data/ESA_WorldCover_10m_2020_v100_N48W129_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N54W120_Map.tif data/ESA_WorldCover_10m_2020_v100_N54W120_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N54W126_Map.tif data/ESA_WorldCover_10m_2020_v100_N54W126_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N51W123_Map.tif data/ESA_WorldCover_10m_2020_v100_N51W123_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N51W132_Map.tif data/ESA_WorldCover_10m_2020_v100_N51W132_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N57W126_Map.tif data/ESA_WorldCover_10m_2020_v100_N57W126_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N57W132_Map.tif data/ESA_WorldCover_10m_2020_v100_N57W132_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N51W117_Map.tif data/ESA_WorldCover_10m_2020_v100_N51W117_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N48W123_Map.tif data/ESA_WorldCover_10m_2020_v100_N48W123_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N57W123_Map.tif data/ESA_WorldCover_10m_2020_v100_N57W123_Map.tif --no-sign-request +aws s3 cp s3://esa-worldcover/v100/2020/map/ESA_WorldCover_10m_2020_v100_N48W126_Map.tif data/ESA_WorldCover_10m_2020_v100_N48W126_Map.tif --no-sign-request + +# merge tiles by building vrt +gdalbuildvrt data/esa_merged.vrt data/ESA_WorldCover_10m_2020_v100_*.tif + +# warp data to BC Albers, writing to compressed geotiff +gdalwarp -co COMPRESS=DEFLATE -co PREDICTOR=2 -co NUM_THREADS=ALL_CPUS -t_srs EPSG:3153 data/esa_merged.vrt esa_bc.tif diff --git a/app/scripts/qaqc/gwells_locationqa.py b/app/scripts/qaqc/gwells_locationqa.py new file mode 100644 index 0000000000..f7877a92b5 --- /dev/null +++ b/app/scripts/qaqc/gwells_locationqa.py @@ -0,0 +1,642 @@ +import csv +import logging +import sys +from zipfile import ZipFile, BadZipFile +from io import BytesIO +from time import sleep +import os +from pathlib import Path +import tarfile +import tempfile +from urllib.parse import urlparse +import urllib.request + + +import fiona +import rasterio +import geopandas as gpd +import pandas as pd +import requests +import click +from thefuzz import fuzz +import bcdata + + +""" +BC Geocoder ADDRESS API + +Overview +https://www2.gov.bc.ca/gov/content/data/geographic-data-services/location-services/geocoder + +Specs +https://github.com/bcgov/api-specs/tree/master/geocoder + +Developer guide +https://github.com/bcgov/api-specs/blob/master/geocoder/geocoder-developer-guide.md + +More +https://www2.gov.bc.ca/assets/gov/data/geographic/location-services/geocoder/understanding_geocoder_results.pdf + +Status +https://stats.uptimerobot.com/KZ3Nvh29l1/787375578 +""" + +# source gwells data file +WELLS_URL = "https://s3.ca-central-1.amazonaws.com/gwells-export/export/v2/gwells.zip" + +# bc geocoder endpoint of interest +GEOCODER_ENDPOINT = "https://geocoder.api.gov.bc.ca/sites/nearest.json" +ADDRESS_COLUMNS = [ + "fullAddress", + "siteName", + "unitDesignator", + "unitNumber", + "unitNumberSuffix", + "civicNumber", + "civicNumberSuffix", + "streetName", + "streetType", + "isStreetTypePrefix", + "streetDirection", + "isStreetDirectionPrefix", + "streetQualifier", + "localityName", + "localityType", + "electoralArea", + "provinceCode", + "locationPositionalAccuracy", + "locationDescriptor", + "siteID", + "blockID", + "fullSiteDescriptor", + "accessNotes", + "siteStatus", + "siteRetireDate", + "changeDate", + "isOfficial", + "distance", +] + +PARCELFABRIC_URL = "https://pub.data.gov.bc.ca/datasets/4cf233c2-f020-4f7a-9b87-1923252fbc24/pmbc_parcel_fabric_poly_svw.zip" + +WELLS_FILENAME = "wells.csv" +PIDMATCH_FILENAME = "pidmatch.csv" +EPSG_3154 = "EPSG:3153" + + +LOG = logging.getLogger(__name__) + + +class ZipCompatibleTarFile(tarfile.TarFile): + """ + Wrapper around TarFile to make it more compatible with ZipFile + Modified from https://github.com/OpenBounds/Processing/blob/master/utils.py + """ + + def infolist(self): + members = self.getmembers() + for m in members: + m.filename = m.name + return members + + def namelist(self): + return self.getnames() + + +def get_compressed_file_wrapper(path): + """From https://github.com/OpenBounds/Processing/blob/master/utils.py""" + ARCHIVE_FORMAT_ZIP = "zip" + ARCHIVE_FORMAT_TAR = "tar" + ARCHIVE_FORMAT_TAR_GZ = "tar.gz" + ARCHIVE_FORMAT_TAR_BZ2 = "tar.bz2" + archive_format = None + if path.endswith(".zip"): + archive_format = ARCHIVE_FORMAT_ZIP + elif path.endswith(".tar.gz") or path.endswith(".tgz"): + archive_format = ARCHIVE_FORMAT_TAR_GZ + elif path.endswith(".tar.bz2"): + archive_format = ARCHIVE_FORMAT_TAR_BZ2 + else: + try: + with ZipFile(path, "r"): + archive_format = ARCHIVE_FORMAT_ZIP + except BadZipFile: + try: + with tarfile.TarFile.open(path, "r"): + archive_format = ARCHIVE_FORMAT_TAR + except tarfile.TarError: + pass + if archive_format is None: + raise Exception("Unable to determine archive format") + + if archive_format == ARCHIVE_FORMAT_ZIP: + return ZipFile(path, "r") + + elif archive_format == ARCHIVE_FORMAT_TAR_GZ: + return ZipCompatibleTarFile.open(path, "r:gz") + + elif archive_format == ARCHIVE_FORMAT_TAR_BZ2: + return ZipCompatibleTarFile.open(path, "r:bz2") + + +def download_file(url, out_path, filename): + """Download and extract a zipfile to unique location""" + out_file = os.path.join(out_path, filename) + if not os.path.exists(os.path.join(out_path, filename)): + LOG.info("Downloading " + url) + parsed_url = urlparse(url) + urlfile = parsed_url.path.split("/")[-1] + _, extension = os.path.split(urlfile) + fp = tempfile.NamedTemporaryFile("wb", suffix=extension, delete=False) + if parsed_url.scheme == "http" or parsed_url.scheme == "https": + res = requests.get(url, stream=True) + if not res.ok: + raise IOError + + for chunk in res.iter_content(1024): + fp.write(chunk) + elif parsed_url.scheme == "ftp": + dl = urllib.request.urlopen(url) + file_size_dl = 0 + block_sz = 8192 + while True: + buffer = dl.read(block_sz) + if not buffer: + break + file_size_dl += len(buffer) + fp.write(buffer) + fp.close() + # extract zipfile + Path(out_path).mkdir(parents=True, exist_ok=True) + LOG.info("Extracting %s to %s" % (fp.name, out_path)) + zipped_file = get_compressed_file_wrapper(fp.name) + zipped_file.extractall(out_path) + zipped_file.close() + layer = fiona.listlayers(os.path.join(out_path, filename))[0] + return (out_file, layer) + + +def get_gwells(outfile=os.path.join("data", WELLS_FILENAME)): + """ + - get wells csv if not already present + - retain only records of interest + - write to file + - return wells as dataframe + """ + if os.path.exists(outfile): + LOG.info(f"Loading {outfile}") + return pd.read_csv(outfile) + else: + r = requests.get(WELLS_URL) + zip_file = ZipFile(BytesIO(r.content)) + dfs = { + text_file.filename: pd.read_csv(zip_file.open(text_file.filename)) + for text_file in zip_file.infolist() + if text_file.filename.endswith(".csv") + } + # only retain records with coordinates + df = dfs["well.csv"].dropna(subset=["latitude_Decdeg", "longitude_Decdeg"]) + # only retain records that are unlicensed + # (we presume locations of licensed wells are correct) + # df = df[df["licenced_status_code"] == "UNLICENSED"] + + # save as intermediate file + df.to_csv(outfile, index=False) + return df + + +def reverse_geocode( + x, + y, + geocoder_api_key, + distance_start=200, + distance_increment=200, + distance_max=2000, +): + """ + Provided a location as x/y coordinates (EPSG:4326), request an address + from BC Geocoder within given distance_start (metres) + + If no result is found, request using an expanding search radius in + distance_increment steps, until distance_max is reached. + + A dict with 'distance' = 99999 is returned if no result is found. + + This could sped up by: + - just make the request using the max distance and derive distance between + source point and returned location + - make requests either in parallel or async + + """ + result = False + distance = distance_start + # expand the search distance until we get a result or hit the max distance + while result is False and distance <= distance_max: + params = { + "point": str(x) + "," + str(y), + "apikey": geocoder_api_key, + "outputFormat": "json", + "maxDistance": distance, + } + r = requests.get(GEOCODER_ENDPOINT, params=params) + LOG.debug(r.request.url) + + # pause for 2s per request if near limit of 1000 requests/min + if int(r.headers["RateLimit-Remaining"]) < 30: + LOG.info("Approaching API limit, sleeping for 2 seconds to refresh.") + sleep(2) + if r.status_code == 200: + result = True + else: + distance = distance + distance_increment + if r.status_code == 200: + address = r.json()["properties"] + address["distance"] = distance + return address + else: + empty_result = dict([(k, "") for k in ADDRESS_COLUMNS]) + empty_result["distance"] = 99999 + return empty_result + + +def pidmatch(wells_gdf): + if os.path.exists(os.path.join("data", PIDMATCH_FILENAME)): + LOG.info( + "Loading data/pidmatch.csv, cached result of wells/parcels PID matching" + ) + pid_distances = gpd.read_file(os.path.join("data", PIDMATCH_FILENAME)) + pid_distances["well_tag_number"] = pid_distances["well_tag_number"].astype(int) + + else: + # load parcel data + LOG.info("Loading data/pmbc_parcel_fabric_poly_svw.gdb") + parcels = gpd.read_file( + os.path.join("data", "pmbc_parcel_fabric_poly_svw.gdb"), + layer="pmbc_parcel_fabric_poly_svw", + ) + # ------ + # ** PID matching ** + # Derive 'distance_to_matching_pid', the distance from well to parcel + # polygon with the same PID + # ------ + # get well records with PID values + wells_with_pid = wells_gdf[wells_gdf["legal_pid"].notna()][ + ["well_tag_number", "legal_pid", "geometry"] + ] + # join to parcel fabric on PID + wells_parcels_pid = pd.merge( + wells_with_pid, + parcels, + how="inner", + left_on="legal_pid", + right_on="PID", + validate="many_to_one" + ) + # find distance from well point to parcel polygon with matching PID + distances_series = wells_parcels_pid["geometry_x"].distance( + wells_parcels_pid["geometry_y"], align=True + ) + # put distance values back into merged df but keep just columns of interest + pid_distances = wells_parcels_pid.assign( + distance_to_matching_pid=distances_series + )[["well_tag_number", "distance_to_matching_pid"]] + # dump to file + pid_distances.to_csv(os.path.join("data", PIDMATCH_FILENAME), index=False) + + return pd.merge(wells_gdf, pid_distances, on="well_tag_number", how="left") + + +def agriculture_overlays(in_gdf): + """Overlay wells with several definitions of agricultural lands or a proxy: + - BTM + - ALR + - ESA land cover + """ + if os.path.exists(os.path.join("data", "agriculture_overlays.csv")): + LOG.info( + "Loading data/agriculture_overlays.csv, cached result of ALR/BTM/ESA overlays" + ) + ag_overlays = gpd.read_file(os.path.join("data", "agriculture_overlays.csv")) + ag_overlays["well_tag_number"] = ag_overlays["well_tag_number"].astype(int) + + else: + LOG.info("Overlaying wells with ALR") + alr = ( + bcdata.get_data("WHSE_LEGAL_ADMIN_BOUNDARIES.OATS_ALR_POLYS", as_gdf=True)[ + ["STATUS", "geometry"] + ] + .to_crs(EPSG_3154) + .rename( + columns={ + "STATUS": "alr_ind", + } + ) + ) + alr_overlay = gpd.sjoin(in_gdf, alr, how="left", predicate="within") + alr_overlay = alr_overlay[["well_tag_number", "alr_ind"]] + + LOG.info("Overlaying wells with BTM") + btm = ( + bcdata.get_data( + "WHSE_BASEMAPPING.BTM_PRESENT_LAND_USE_V1_SVW", as_gdf=True + )[["PRESENT_LAND_USE_LABEL", "geometry"]] + .to_crs(EPSG_3154) + .rename( + columns={ + "PRESENT_LAND_USE_LABEL": "btm_label", + } + ) + ) + btm_overlay = gpd.sjoin(in_gdf, btm, how="left", predicate="within") + btm_overlay = btm_overlay[["well_tag_number", "btm_label"]] + + # overlay input with ESA land cover + LOG.info("Overlaying wells with ESA 10m landcover (2020)") + landclass_lookup = { + 0: "NULL", + 10: "Tree cover", + 20: "Shrubland", + 30: "Grassland", + 40: "Cropland", + 50: "Built-up", + 60: "Bare/sparse vegetation", + 70: "Snow and ice", + 80: "Permanent water bodies", + 90: "Herbaceous wetland", + 95: "Mangroves", + 100: "Moss and lichen", + } + esa = in_gdf.copy() + esa.index = range(len(in_gdf)) + coords = [(x, y) for x, y in zip(esa.geometry.x, in_gdf.geometry.y)] + raster = rasterio.open("data/esa_bc.tif") + esa["esa_landclass"] = [landclass_lookup[x[0]] for x in raster.sample(coords)] + esa = esa[["well_tag_number", "esa_landclass"]] + + # join all three dfs together + a = pd.merge(alr_overlay, btm_overlay, "left", on="well_tag_number") + b = pd.merge(a, esa, "left", on="well_tag_number") + + # make sure we only have columns of interest + ag_overlays = b[["well_tag_number", "alr_ind", "btm_label", "esa_landclass"]] + + # write to csv + ag_overlays.to_csv("data/agriculture_overlays.csv") + + return ag_overlays + + +def compare_strings(x): + return fuzz.token_set_ratio(x[0], x[1]) + + +@click.group() +def cli(): + """ + This is the main command group for the CLI. + + The function `cli` is decorated with `@click.group()`, which turns it into a command group. + This group will serve as the base for nesting other sub-commands. The `pass` statement is used + here because the function itself does not need to execute any code. Its primary purpose is to + serve as a foundation for the CLI structure. Sub-commands will be attached to this group, + and they will be the ones performing the actual operations or functionalities. + """ + pass + + +@cli.command() +def download(): + """Download required data to data folder""" + Path("data").mkdir(parents=True, exist_ok=True) + get_gwells(os.path.join("data", WELLS_FILENAME)) + download_file(PARCELFABRIC_URL, "data", "pmbc_parcel_fabric_poly_svw.gdb") + + +@cli.command() +@click.argument("geocoder_api_key", envvar="GEOCODER_API_KEY") +@click.option( + "--out_file", + "-o", + default=os.path.join("data", "wells_geocoded.csv"), + help="Name of output file.", +) +def geocode(geocoder_api_key, out_file): + """Reverse geocode well locations with BC Geocoder API""" + # only process if output file does not already exist + if not os.path.exists(out_file): + # get wells csv as pandas dataframe + df = get_gwells(os.path.join("data", WELLS_FILENAME)) + + # extract just id and coords + well_locations = df[ + ["well_tag_number", "longitude_Decdeg", "latitude_Decdeg"] + ].to_dict("records") + + LOG.info("Reverse geocoding well locations") + with open(out_file, "w", newline="") as csvfile: + writer = csv.DictWriter( + csvfile, fieldnames=ADDRESS_COLUMNS + ["well_tag_number"] + ) + writer.writeheader() + with click.progressbar(well_locations) as bar: + for row in bar: + r = reverse_geocode( + row["longitude_Decdeg"], + row["latitude_Decdeg"], + geocoder_api_key, + ) + r["well_tag_number"] = row["well_tag_number"] + writer.writerow(r) + + +@cli.command() +def qa(): + """Create several columns to use for location QA + - distance from well pt to parcel with matching PID + - wells street address / geocoder street address similarity + - wells location description / geocoder streeet address similarity + - wells city / geocoder locality similarity + + While running the analysis, reports on a few counts. + """ + # load source wells data + gwells_df = get_gwells() + + # create a copy + wells_copy = gwells_df.copy() + wells = gpd.GeoDataFrame( + wells_copy, + geometry=gpd.points_from_xy( + x=wells_copy.longitude_Decdeg, y=wells_copy.latitude_Decdeg, crs="EPSG:4326" + ), + ).to_crs(EPSG_3154) + # convert id to integer + wells["well_tag_number"] = wells["well_tag_number"].astype(int) + # retain just columns of interest + wells = wells[ + [ + "well_tag_number", + "street_address", + "city", + "well_location_description", + "legal_pid", + "geometry", + ] + ] + + # get NR regions/districts + nrd = ( + bcdata.get_data("WHSE_ADMIN_BOUNDARIES.ADM_NR_DISTRICTS_SPG", as_gdf=True)[ + ["DISTRICT_NAME", "REGION_ORG_UNIT_NAME", "geometry"] + ] + .to_crs(EPSG_3154) + .rename( + columns={ + "DISTRICT_NAME": "nr_district_name", + "REGION_ORG_UNIT_NAME": "nr_region_name", + } + ) + ) + # overlay with wells + wells_nrd = gpd.sjoin(wells, nrd, how="left", predicate="within") + + # load geocode results as string, retain only columns of interest + geocode_df = pd.read_csv(os.path.join("data", "wells_geocoded.csv"), dtype=str)[ + [ + "well_tag_number", + "fullAddress", + "civicNumber", + "civicNumberSuffix", + "streetName", + "streetType", + "isStreetTypePrefix", + "streetDirection", + "isStreetDirectionPrefix", + "streetQualifier", + "localityName", + "distance", + ] + ].rename(columns={"distance": "distance_geocode"}) + # convert tag and distance_geocode to integer + geocode_df["well_tag_number"] = geocode_df["well_tag_number"].astype(int) + geocode_df["distance_geocode"] = geocode_df["distance_geocode"].astype(int) + + # combine wells and geocode results + wells_nrd_geocoded = pd.merge(wells_nrd, geocode_df, "inner", on="well_tag_number") + + # match wells pid values to parcels pid values + wells_nrd_geocoded_pidmatched = pidmatch(wells_nrd_geocoded) + + scoring = wells_nrd_geocoded_pidmatched # shorter name + + # ------ + # ** Address matching ** + # ------ + LOG.info("Generating address matching scores") + + # before trying matching, clean the addresses by filling in nulls and + # do some very simple string standardization + scoring["street_address"] = scoring["street_address"].fillna("") + scoring["well_location_description"] = scoring["well_location_description"].fillna( + "" + ) + scoring["city"] = scoring["city"].fillna("") + # lowercasify the scoring address strings + scoring["street_address"] = scoring["street_address"].str.lower() + # abbreviate road types to match geocoder + street_abbreviations = { + "road": "rd", + "drive": "dr", + "avenue": "ave", + "highway": "hwy", + "street": "st", + "boulevard": "blvd", + "crescent": "cres", + "frontage": "frtg", + "place": "pl", + "court": "crt", + "terrace": "terr", + "lookout": "lkout", + "heights": "hts", + } + for k in street_abbreviations: + scoring["street_address"] = scoring["street_address"].str.replace( + k, street_abbreviations[k] + ) + # combine geocoder number/name/type/direction into a single slug + t = scoring[["civicNumber", "streetName", "streetType", "streetDirection"]] + scoring["streetAddress"] = t.apply( + lambda x: " ".join(x.dropna().astype(str).values), axis=1 + ) + + # + # "score_address" + # + # compares gwells address to geocoder address + t = scoring[["street_address", "streetAddress"]] + scoring["score_address"] = t.apply(compare_strings, axis=1) + + # + # "score_location_description" + # + # compares well_location_description with geocoder full street address + t = scoring[["well_location_description", "fullAddress"]] + scoring["score_location_description"] = t.apply(compare_strings, axis=1) + + # + # "city_score" + # + # compares gwells city to geocoder locality + t = scoring[["city", "localityName"]] + scoring["score_city"] = t.apply(compare_strings, axis=1) + + # extract only columns of interest + scoring = scoring[ + [ + "well_tag_number", + "nr_district_name", + "nr_region_name", + "fullAddress", + "streetAddress", + "civicNumber", + "civicNumberSuffix", + "streetName", + "streetType", + "isStreetTypePrefix", + "streetDirection", + "isStreetDirectionPrefix", + "streetQualifier", + "localityName", + "distance_geocode", + "distance_to_matching_pid", + "score_address", + "score_location_description", + "score_city", + ] + ] + + # Join the NR/geocoding/pidmatch scoring df back to source wells + out_df = pd.merge(gwells_df, scoring, "left", on="well_tag_number") + + # addtional QA - + # find records that have been cross referenced + # (fuzzy match scoring doesn't seem appropriate here, we can just + # search for exact matches of several permutations to catch most) + out_df["xref_ind"] = ( + out_df["comments"] + .str.upper() + .fillna("") + .str.contains("CROSS R|CROSS-R|REF'D|REFERENCED|REFD|XREF|X-R|X R") + ) + + # finally, overlay with ALR/BTM/ESA Landcover to find wells in agricultural areas + # ag_overlays = agriculture_overlays(wells) + # out_df = pd.merge(out_df, ag_overlays, "left", on="well_tag_number") + + # and dump results to file + LOG.info("Writing output file gwells_locationqa.csv") + out_df.to_csv("gwells_locationqa.csv", index=False) + + +if __name__ == "__main__": + cli() diff --git a/app/scripts/qaqc/requirements.txt b/app/scripts/qaqc/requirements.txt new file mode 100644 index 0000000000..bd4c919c58 --- /dev/null +++ b/app/scripts/qaqc/requirements.txt @@ -0,0 +1,7 @@ +requests>=2.26 +rasterio +geopandas>=0.10 +jupyterlab>=3.2.1 +python-levenshtein==0.12.2 +thefuzz==0.19.0 +bcdata>=0.4.5