diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..862b2ce --- /dev/null +++ b/404.html @@ -0,0 +1,1260 @@ + + + + + + + + + + + + + + + + + + + + + ASF SAR Manual de Búsqueda de Datos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..a0483b5 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +docs.asf.alaska.edu diff --git a/api/basics.key b/api/basics.key new file mode 100644 index 0000000..54f9f39 --- /dev/null +++ b/api/basics.key @@ -0,0 +1 @@ +{{ SEARCH_API_BASIC_1 }} \ No newline at end of file diff --git a/api/basics/index.html b/api/basics/index.html new file mode 100644 index 0000000..09414d8 --- /dev/null +++ b/api/basics/index.html @@ -0,0 +1,1387 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Search API Basics - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Search API Basics#

+

Building a Search API query consists of 3 basic steps:

+
    +
  1. Use the Search API base URL: https://api.daac.asf.alaska.edu
  2. +
  3. Pick an endpoint. All available endpoints are listed in the Keywords documentation. The Search endpoint uses this base URL: https://api.daac.asf.alaska.edu/services/search/param
  4. +
  5. Build your query using keywords
  6. +
+

The completed URL will be in this format: https://api.daac.asf.alaska.edu/services/search/param?keyword1=value1&keyword2=value2,value3&keyword3=value4-6

+

Once your query is built, you may execute by copy/pasting into a browser window, a command line interface, or by using a program. More details on various options and some syntax tips can be found in the Search API Tools documentation.

+

Downloading Data

+

In order to download data, you will need a NASA EOSDIS Earthdata Login account. Earthdata accounts are free. Go to Earthdata Login — Create Profile to create an account.

+

You will be prompted to accept the ASF End-User License Agreement and set a Study Area to complete your new user setup.

+

Note: A research agreement is required for access to JERS-1 and RADARSAT-1 data. Please complete the required Research Agreement, or contact user support at the email or number below.

+

Next Steps

+

See Search API Keywords to get started on building a query, or see the Tools page for some examples.

+

Alternatively, you may wish to use asf_search, a Python package for performing searches of the ASF catalog. It also offers baseline functionality and download support. Additionally, numerous constants are provided to ease the search process. It is available through PyPi and Conda. More information can be found here.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/api/changelog.key b/api/changelog.key new file mode 100644 index 0000000..44abf36 --- /dev/null +++ b/api/changelog.key @@ -0,0 +1 @@ +{{ CHANGELOG_2 }} \ No newline at end of file diff --git a/api/changelog/index.html b/api/changelog/index.html new file mode 100644 index 0000000..a4ead22 --- /dev/null +++ b/api/changelog/index.html @@ -0,0 +1,1484 @@ + + + + + + + + + + + + + + + + + + + + + + + + + What's New - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + +

What's New#

+

Dataset keyword#

+

The new "dataset" keyword is the preferred alternative for platform searches. It allows results from multiple platforms at once. More information can be found here.

+

New Python package for performing searches#

+

asf_search is a Python package for performing searches of the ASF catalog. In addition, it offers baseline functionality and download support. It is available through PyPi and Conda. More information can be found here.

+

Multiple Endpoints Available#

+

In addition to the Search endpoint, we have multiple endpoints available for all of your Search API needs. Below is a brief overview of what's available. More details on these endpoints and how to use them can be found on the Keywords page.

+

Baseline Endpoint

+

This endpoint can be used to search for baseline data using specific reference scenes.

+

WKT Endpoints

+

The WKT validation endpoint will validate and repair a WKT input. The GeoSpatial Files to WKT endpoint will accept a POST request with files attached. It will return the parsed WKT from the file, as well as the repaired wrapped and unwrapped WKT.

+

Date Parser Endpoint

+

This endpoint can be used to check how dates are parsed by the Search API.

+

Mission List Endpoint

+

This endpoint lists all missions (also known as campaigns or collections) for all datasets.

+

Health Endpoint

+

This endpoint is used to check the Search API health. It also provides information on CMR health.

+

Preferred Search API Output Format#

+

GeoJSON is the preferred Search API output format. You can specify the output format with keyword "output". If you find a required field that is not included in GeoJSON output, please contact ASF using the info below or reach the team directly at uaf-asf-discovery@alaska.edu.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/api/cookbook.key b/api/cookbook.key new file mode 100644 index 0000000..9cb01b5 --- /dev/null +++ b/api/cookbook.key @@ -0,0 +1 @@ +{{ COOKBOOK_1 }} \ No newline at end of file diff --git a/api/cookbook/index.html b/api/cookbook/index.html new file mode 100644 index 0000000..3362de8 --- /dev/null +++ b/api/cookbook/index.html @@ -0,0 +1,1508 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Cookbook - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Search API Tips & Tricks#

+

This is a collection of some tips & tricks for the Search API!

+

New Python package for performing searches#

+

asf_search is a Python package for performing searches of the ASF catalog. In addition, it offers baseline functionality and download support. It is available through PyPi and Conda. More information can be found here.

+

Rate Limitation on Search Endpoint#

+

There has been a rate limitation instituted on the search endpoint. The rate limitation is per IP and is currently 250 queries per minute. Upon hitting the limit, further queries will yield a HTTP 429 with an error message. Check to see if your queries are returning a small number of results. If so, you can refine your parameters to combine result sets into larger groups and then post-process those results locally. For instance, instead of searching on a small area of interest with an individual query for each day, select a larger date range in order to create a single query, then split the results apart after they have been retrieved.

+

Vertex Copy/Paste Search API URL#

+

Have you have completed a geo search in Vertex, that you'd like to replicate in a Search API query? Click the Down Arrow under the Max Results. Choose "API URL...".

+

Here you can see the Search API URL you would use to replicate the search. You may change the maxResults and output format. Once you are satisfied, click the copy icon. Now you can paste the query into a browser or command line interface to execute it.

+

Find the Product_List Value in Vertex#

+

The product/file name is listed in Vertex Search Results, under the Files detail column. You can click the Copy icon to copy the File ID. You can also copy all File IDs from your Download Queue in Vertex. Once you have your desired list of files, you can find them via the Search API using the product_list keyword.

+

Search Results Can Become Search Area#

+

You can turn your search results into a search area. First, export your search results as GeoJSON or KML output format. Next, import your file into Vertex geo search. Vertex will extract the AOI from your file. If desired, you can add filters and can save your search filters or the search itself.

+

Verify Your Query is Returning the Correct Number of Results#

+

Would you like to verify that your query has returned the correct number of results? Change your output to "output=count" to verify. If the count does not match, consider narrowing your search by using more keywords, or by using keyword “maxResults” to limit it. You may also try shortening the date range to split your search into a series of smaller searches.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/api/keywords.key b/api/keywords.key new file mode 100644 index 0000000..7ea7893 --- /dev/null +++ b/api/keywords.key @@ -0,0 +1 @@ +{{ KEYWORDS_1 }} \ No newline at end of file diff --git a/api/keywords/index.html b/api/keywords/index.html new file mode 100644 index 0000000..dd6bcd1 --- /dev/null +++ b/api/keywords/index.html @@ -0,0 +1,2368 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Search API Keywords & Endpoints - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Search API Keywords#

+

Consider using our new Python package, asf_search. asf_search can be used to perform searches of the ASF catalog, and it offers baseline functionality and download support. Additionally, numerous constants are provided to ease the search process. Currently, we provide constants for platform, instrument, beam mode, flight direction, polarization, and processing level. More information can be found here.

+

Keywords are used to find the desired data. Use as many or as few keywords as needed. Available keywords and descriptions are listed below for each Search API endpoint. Keywords are case sensitive.

+

Note: Any errors will be returned in JSON format.

+

Search Endpoint#

+

https://api.daac.asf.alaska.edu/services/search/param

+

Dataset Parameters#

+
    +
  • +

    dataset

    + +
  • +
  • +

    platform

    +
      +
    • See also 'dataset'. Dataset is the preferred keyword when possible.
    • +
    • This keyword has constants provided through asf_search. More information can be found here.
    • +
    • See also 'instrument'
    • +
    • Remote sensing platform that acquired the data. Sentinel-1 and ERS have multiple remote sensing platforms, and you may choose whether to specify a specific platform. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • platform=ALOS
      • +
      • platform=SA,SB
      • +
      • platform=S1
      • +
      +
    • +
    • Values:
        +
      • ALOS, A3, AIRSAR, AS, ERS, ERS-1, E1, ERS-2, E2, JERS-1, J1, RADARSAT-1, R1, SEASAT, SS, S1, Sentinel, Sentinel-1, Sentinel-1A, SA, Sentinel-1B, Sentinel-1 Interferogram (BETA), SB, SIR-C, SMAP, SP, UAVSAR, UA
      • +
      +
    • +
    +
  • +
  • +

    instrument

    +
      +
    • See also 'dataset'. Dataset is the preferred keyword when possible.
    • +
    • This keyword has constants provided through asf_search. More information can be found here.
    • +
    • See also 'platform'
    • +
    • Remote sensing instrument that acquired the data. For some platforms, such as ALOS, there are multiple instruments to choose from.
    • +
    • Example:
        +
      • ALOS: instrument=PALSAR
      • +
      • ALOS: instrument=AVNIR-2
      • +
      +
    • +
    • Values:
        +
      • C-SAR, PALSAR, AVNIR-2
      • +
      +
    • +
    +
  • +
  • +

    absoluteOrbit

    +
      +
    • This keyword is also available through asf_search.
    • +
    • For ALOS, ERS-1, ERS-2, JERS-1, RADARSAT-1, Sentinel-1A, and Sentinel-1B this value corresponds to the orbit count within the orbit cycle. For UAVSAR it is the Flight ID. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • RADARSAT: absoluteOrbit=25436
      • +
      • PALSAR: absoluteOrbit=25436-25445,25450
      • +
      • UAVSAR: absoluteOrbit=12006
      • +
      +
    • +
    +
  • +
  • +

    asfframe

    +
      +
    • This keyword is also available through asf_search.
    • +
    • See also 'frame'
    • +
    • This is primarily an ASF / JAXA frame reference. However, some platforms use other conventions. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • asfframe=300 or asfframe=2845-2855 or asfframe=2800,2845-2855
      • +
      +
    • +
    • Values:
        +
      • ERS, JERS, RADARSAT: ASF frames 0 to 900
      • +
      • ALOS PALSAR: JAXA frames 0 to 7200
      • +
      • SEASAT: ESA-like frames 0208 to 3458 (must use a leading zero for frames 208-999)
      • +
      • Sentinel-1: In-house values 0 to 1184
      • +
      +
    • +
    +
  • +
  • +

    maxBaselinePerp

    +
      +
    • For interferometric SAR (InSAR) analysis, Perpendicular Baseline is the spatial distance between the first and second observations measured perpendicular to the satellite look direction and provides an indication of the sensitivity to topographic height.
    • +
    • Works for ERS-1, ERS-2, JERS, RADARSAT-1, ALOS PALSAR. (Not Sentinel-1)
    • +
    • Example:
        +
      • maxBaselinePerp=1500 or maxBaselinePerp=50.5
      • +
      +
    • +
    +
  • +
  • +

    minBaselinePerp

    +
      +
    • For interferometric SAR (InSAR) analysis, Perpendicular Baseline is the spatial distance between the first and second observations measured perpendicular to the satellite look direction and provides an indication of the sensitivity to topographic height.
    • +
    • Works for ERS-1, ERS-2, JERS, RADARSAT-1, ALOS PALSAR. (Not Sentinel-1)
    • +
    • Example:
        +
      • minBaselinePerp=100 or minBaselinePerp=50.5
      • +
      +
    • +
    +
  • +
  • +

    beamMode

    +
      +
    • This keyword has constants provided through asf_search. More information can be found here.
    • +
    • The beam mode used to acquire the data. See also beamSwath. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • beamMode=FBS or beamMode=EW,IW or beamMode=ScanSAR+Wide
      • +
      +
    • +
    • Values:
        +
      • AIRSAR: 3FP, ATI, XTI
      • +
      • ALOS: FBD, FBS, PLR, WB1, WB2, DSN
      • +
      • ERS-1: Standard, STD
      • +
      • ERS-2: Standard, STD
      • +
      • JERS-1: Standard, STD
      • +
      • RADARSAT-1: Standard, STD, Fine, High, Low, Wide, Narrow, ScanSAR+Wide, ScanSAR+Narrow
      • +
      • SEASAT: Standard, STD
      • +
      • SMAP: Standard, STD
      • +
      • Sentinel-1A: EW, IW, S1, S2, S3, S4, S5, S6, WV
      • +
      • Sentinel-1B: EW, IW, S1, S2, S3, S4, S5, S6, WV
      • +
      • UAVSAR: POL, RPI
      • +
      +
    • +
    +
  • +
  • +

    beamSwath

    +
      +
    • This keyword is also available through asf_search.
    • +
    • BeamSwath encompasses a look angle and beam mode. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • beamSwath=0
      • +
      • beamSwath=FN1, FN2, FN3, FN4, FN5
      • +
      +
    • +
    • Values:
        +
      • AIRSAR: 3FP, ATI, XTI
      • +
      • ALOS: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20
      • +
      • AVNIR-2: OBS
      • +
      • ERS-1: STD
      • +
      • ERS-2: STD
      • +
      • JERS-1: STD
      • +
      • RADARSAT-1: FN1, FN2, FN3, FN4, FN5, SNA, SNB, ST1, ST2, ST3, ST4, ST5, ST6, ST7, SWA, SWB, WD1, WD2, WD3, EH3, EH4, EH6, EL1
      • +
      • SEASAT: STD
      • +
      • Sentinel-1A: EW, IW, S1, S2, S3, S4, S5, S6, SLC, WV
      • +
      • Sentinel-1B: EW, IW, S1, S2, S3, S4, S5, S6, SLC, WV
      • +
      • UAVSAR: POL, RPI
      • +
      +
    • +
    +
  • +
  • +

    collectionName

    +
      +
    • This keyword is also available through asf_search.
    • +
    • For UAVSAR and AIRSAR data collections only. Search by the mission/campaign name. You may specify a single value. For a list of available collections, refer to the Mission List Endpoint below.
    • +
    • Example:
        +
      • UAVSAR: collectionName=ABoVE
      • +
      • AIRSAR: collectionName=collectionName=Akiyoshi,+Japan
      • +
      +
    • +
    +
  • +
  • +

    maxDoppler

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Doppler provides an indication of how much the look direction deviates from the ideal perpendicular flight direction acquisition.
    • +
    • Example:
        +
      • maxDoppler=1500 or maxDoppler=1500.5
      • +
      +
    • +
    +
  • +
  • +

    minDoppler

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Doppler provides an indication of how much the look direction deviates from the ideal perpendicular flight direction acquisition.
    • +
    • Example:
        +
      • minDoppler=100 or minDoppler=1500.5
      • +
      +
    • +
    +
  • +
  • +

    maxFaradayRotation

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Rotation of the polarization plane of the radar signal impacts imagery. HH and HV signals become mixed. One-way rotations exceeding 5° are likely to significantly reduce the accuracy of geophysical parameter recovery, such as forest biomass.
    • +
    • Example:
        +
      • maxFaradayRotation=3.5
      • +
      +
    • +
    +
  • +
  • +

    minFaradayRotation

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Rotation of the polarization plane of the radar signal impacts imagery. HH and HV signals become mixed. One-way rotations exceeding 5° are likely to significantly reduce the accuracy of geophysical parameter recovery, such as forest biomass.
    • +
    • Example:
        +
      • minFaradayRotation=2
      • +
      +
    • +
    +
  • +
  • +

    flightDirection

    +
      +
    • This keyword has constants provided through asf_search. More information can be found here.
    • +
    • Satellite orbit direction during data acquisition. You may specify a single value.
    • +
    • Example:
        +
      • flightDirection=DESCENDING
      • +
      +
    • +
    • Values:
        +
      • A, ASC, ASCENDING, D, DESC, DESCENDING
      • +
      +
    • +
    +
  • +
  • +

    flightLine

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Specify a flightline for UAVSAR or AIRSAR. You may specify a single value.
    • +
    • Example:
        +
      • UAVSAR: flightLine=05901
      • +
      • AIRSAR: flightLine=gilmorecreek045-1.93044
      • +
      +
    • +
    +
  • +
  • +

    frame

    +
      +
    • This keyword is also available through asf_search.
    • +
    • See also 'asfframe'
    • +
    • ESA-referenced frames are offered to give users a universal framing convention. Each ESA frame has a corresponding ASF frame assigned. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • frame=300
      • +
      • frame=300-400
      • +
      • frame=300,303,305
      • +
      • frame=300,303,305-315
      • +
      +
    • +
    • Values:
        +
      • Any number from 0 to 7200.
      • +
      +
    • +
    +
  • +
  • +

    fullBurstID

    +
      +
    • Used for Sentinel-1 burst products. Each value represents all burst products over a single sub-swath, corresponding to a near-perfect frame-aligned stack. This value is useful for baseline stacking. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • single value: fullBurstID=017_034465_IW2
      • +
      • list of values: fullBurstID=017_034465_IW2,079_167884_IW1
      • +
      +
    • +
    +
  • +
  • +

    granule_list

    +
      +
    • Comma-separated list of specific scenes (granules). Large lists will need to utilize a POST request.
    • +
    • granule_list may not be used in conjuction with other keywords, however, it may be used with the output keyword.
    • +
    • Example:
        +
      • granule_list=ALPSRP111041130, +S1B_IW_GRDH_1SDV_20161124T032008_20161124T032033_003095_005430_9906
      • +
      +
    • +
    +
  • +
  • +

    groupid

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Comma-separated list of specific group IDs. For some datasets, the group ID is the same as the scene name. For others, such as Sentinel-1, the group ID is unique for a group of scenes. The group ID value is included in GeoJSON, JSON, and CSV outputs.
    • +
    • Example:
        +
      • groupid=S1A_IWDV_0112_0118_037147_150
      • +
      +
    • +
    +
  • +
  • +

    lookDirection

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Left or right direction of data acquisition. You may specify a single value.
    • +
    • Example:
        +
      • lookDirection=L
      • +
      +
    • +
    • Values:
        +
      • R, RIGHT, L, LEFT
      • +
      +
    • +
    +
  • +
  • +

    maxInsarStackSize

    +
      +
    • An InSAR stack is composed of all SAR granules that cover the same geographic region, are from the same platform, and were acquired with the same beam mode, look angle, and bandwidth. To obtain InSAR stacks containing a certain number of SAR granules specify a min, max, or both.
    • +
    • Works for ERS-1, ERS-2, JERS, RADARSAT-1, ALOS PALSAR. (Not Sentinel-1)
    • +
    • Example:
        +
      • maxInsarStackSize=175
      • +
      +
    • +
    +
  • +
  • +

    minInsarStackSize

    +
      +
    • An InSAR stack is composed of all SAR granules that cover the same geographic region, are from the same platform, and were acquired with the same beam mode, look angle, and bandwidth. To obtain InSAR stacks containing a certain number of SAR granules specify a min, max, or both.
    • +
    • Works for ERS-1, ERS-2, JERS, RADARSAT-1, ALOS PALSAR. (Not Sentinel-1)
    • +
    • Example:
        +
      • minInsarStackSize=20
      • +
      +
    • +
    +
  • +
  • +

    offNadirAngle

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Off-nadir angles for ALOS PALSAR. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • offNadirAngle=21.5
      • +
      • offNadirAngle=9.7-14
      • +
      • offNadirAngle=21.5,23.1,20.5-24.2
      • +
      +
    • +
    • Values:
        +
      • Most common: 21.5, 23.1, 27.1, 34.3
      • +
      • Other: 9.7, 9.9, 13.8, 14, 16.2, 17.3, 17.9, 18, 19.2, 20.5, 21.5, 23.1, 24.2, 24.6, 25.2, 25.8, 25.9, 26.2, 27.1, 28.8, 30.8, 34.3, 36.9, 38.8, 41.5, 43.4, 45.2, 46.6, 47.8, 49, 50, 50.8
      • +
      +
    • +
    +
  • +
  • +

    operaBurstID

    +
      +
    • Used for Opera-S1 products. Each value identifies the specific burst for the product. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • single value: operaBurstID=T078-165486-IW2
      • +
      • list of values: operaBurstID=T078_165486_IW2, T078_165485_IW2
      • +
      +
    • +
    +
  • +
  • +

    polarization

    +
      +
    • This keyword has constants provided through asf_search. More information can be found here.
    • +
    • A property of SAR electromagnetic waves that can be used to extract meaningful information about surface properties of the earth. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • polarization=VV
      • +
      • polarization=VV,HH
      • +
      • polarization=VV+VH
      • +
      • polarization=Dual+VV
      • +
      +
    • +
    • Values:
        +
      • AIRSAR: FULL
      • +
      • ALOS: QUADRATURE, HH+5SCAN, HH, HH+4SCAN, VV, HH+3SCAN, FULL, HH+HV, VV+VH
      • +
      • ERS-1: VV
      • +
      • ERS-2: VV
      • +
      • JERS-1: HH
      • +
      • RADARSAT-1: HH
      • +
      • SEASAT: HH
      • +
      • Sentinel-1A: VV, VV+VH, Dual VV, VV+VH, Dual HV, Dual HH, HH, HH+HV, VV, Dual VH
      • +
      • Sentinel-1B: VV, VV+VH, Dual VV, VV+VH, Dual HV, Dual HH, HH, HH+HV, VV, Dual VH
      • +
      • UAVSAR: FULL, HH
      • +
      +
    • +
    +
  • +
  • +

    processingLevel

    +
      +
    • This keyword has constants provided through asf_search. More information can be found here.
    • +
    • Level to which the data has been processed, also type of product. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • processingLevel=L0,L1
      • +
      +
    • +
    • Values:
        +
      • AIRSAR: 3FP, LTIF, PTIF, CTIF, PSTOKES, DEM, CSTOKES, JPG, LSTOKES
      • +
      • ALOS: L1.0, L1.1, L1.5, L2.2, RTC_LOW_RES, RTC_HI_RES, KMZ
      • +
      • ERS-1: L0, L1
      • +
      • ERS-2: L0, L1
      • +
      • JERS-1: L0, L1
      • +
      • OPERA-S1: RTC, CSLC, RTC_STATIC, CSLS_STATIC
      • +
      • RADARSAT-1: L0, L1
      • +
      • SEASAT: L1, GEOTIFF
      • +
      • Sentinel-1A: GRD_HS, GRD_HD, GRD_MS, GRD_MD, GRD_FD, SLC, RAW, OCN, METADATA_RAW, METADATA_SLC, METADATA_GRD_HD, METADATA_GRD_MD, METADATA_GRD_MS, METADATA_GRD_HS, METADATA_OCN
      • +
      • Sentinel-1B: GRD_HS, GRD_HD, GRD_MS, GRD_MD, GRD_FD, SLC, RAW, OCN, METADATA_RAW, METADATA_SLC, METADATA_GRD_HD, METADATA_GRD_MD, METADATA_GRD_MS, METADATA_GRD_HS, METADATA_OCN
      • +
      • Sentinel-1 InSAR: GUNW_STD, GUNW_AMP, GUNW_CON, GUN_COH, GUNW_UNW
      • +
      • Sentinel-1 Bursts: BURST
      • +
      • SIR-C: SLC, METADATA_SLC
      • +
      • SMAP: L1A_Radar_RO_QA, L1A_Radar_RO_HDF5, L1B_S0_LoRes_HDF5, L1B_S0_LoRes_QA, L1B_S0_LoRes_ISO_XML, L1A_Radar_QA, L1A_Radar_RO_ISO_XML, L1C_S0_HiRes_ISO_XML, L1C_S0_HiRes_QA, L1C_S0_HiRes_HDF5, L1A_Radar_HDF5
      • +
      • UAVSAR: KMZ, PROJECTED, PAULI, PROJECTED_ML5X5, STOKES, AMPLITUDE, COMPLEX, DEM_TIFF, PROJECTED_ML3X3, METADATA, AMPLITUDE_GRD, INTERFEROMETRY, INTERFEROMETRY_GRD, INC, SLOPE
      • +
      +
    • +
    +
  • +
  • +

    product_list

    +
      +
    • Comma-separated list of specific files (products). Large lists will need to utilize a POST request. You can find the product_list values for any file in the GeoJSON (fileID) or JSON (product_file_id) outputs. It is also available from CMR, in the granuleUR field. It is guaranteed to be a unique indentifier in CMR. You can also find the product_list value in Vertex! See the Cookbook page for this Tip & more.
    • +
    • product_list may not be used in conjuction with other keywords, however, it may be used with the output keyword.
    • +
    • Example:
        +
      • product_list=ALAV2A276512920, +S1A_IW_SLC__1SDV_20210614T154839_20210614T154905_038338_048643_D7E4-SLC
      • +
      +
    • +
    +
  • +
  • +

    relativeOrbit

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Path or track of satellite during data acquisition. For UAVSAR it is the Line ID. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • relativeOrbit=500,550-580
      • +
      • UAVSAR: relativeOrbit=05905
      • +
      +
    • +
    • Values:
        +
      • ALOS: 1-671
      • +
      • ERS-1: 0-2410
      • +
      • ERS-2: 0-500
      • +
      • JERS-1: 0-658
      • +
      • RADARSAT-1: 0-342
      • +
      • SEASAT: 1-243
      • +
      • UAVSAR: various
      • +
      +
    • +
    +
  • +
+

Geospatial Parameters#

+
    +
  • +

    bbox

    +
      +
    • Deprecation Notice: This keyword will be deprecated. Please use 'intersectsWith' instead.
    • +
    • Bounding boxes define an area using two long/lat points. The Bounding box parameters are 4 comma-separated numbers: lower left longitude,latitude, and upper right longitude,latitude. This is a great choice for very wide search areas.
    • +
    • Example:
        +
      • bbox=-150.2,65.0,-150.1,65.5
      • +
      +
    • +
    +
  • +
  • +

    intersectsWith

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Search by polygon, a line segment (“linestring”), or a point defined in 2-D Well-Known Text (WKT). Each polygon must be explicitly closed, i.e. the first vertex and the last vertex of each listed polygon must be identical. Coordinate pairs for each vertex are in decimal degrees: longitude is followed by latitude.
    • +
    • Notes:
        +
      • Does not support multi-polygon, multi-line or multi-point.
      • +
      • Polygon holes are ignored
      • +
      • This keyword also accepts a POST request
      • +
      +
    • +
    • Example (Note: The spaces and parentheses below need to be URL encoded first):
        +
      • intersectsWith=polygon((-119.543 37.925, -118.443 37.7421, -118.682 36.8525, -119.77 37.0352, -119.543 37.925 ))
      • +
      • intersectsWith=linestring(-119.543 37.925, -118.443 37.7421)
      • +
      • intersectsWith=point(-119.543, 37.925)
      • +
      +
    • +
    • Properly URL encoded:
        +
      • intersectsWith=point%28-119.543+37.925%29
      • +
      +
    • +
    +
  • +
  • +

    polygon

    +
      +
    • Deprecation Notice: This keyword will be deprecated. Please use 'intersectsWith' instead.
    • +
    • Bounding polygon in the digital long/lat format; enter coordinates in counter clockwise direction, repeat the first point at the end to close the polygon: in the format ABCDA
    • +
    • Example:
        +
      • polygon=-155.08,65.82,-153.5,61.91,-149.50,63.07,-149.94,64.55,-153.28,64.47,-155.08,65.82
      • +
      +
    • +
    +
  • +
+

Shape Validation#

+

If the AOI specified is its own Minimum Bounding Rectangle (MBR) in a mercator projection, the search results returned will instersect with the AOI in a mercator projection, regardless of width. This remains the case even if the international dateline is crossed within the AOI.

+

In order for an AOI to be considered its own MBR, it must meet the following criteria:

+
    +
  • Each vertex shares a latitude or longitude with its neighbors
  • +
  • East/West points share longitude
  • +
  • North/South points share latitude
  • +
+

AOIs that do not fit this criteria will have their points connected along great circles.

+

In addition, all AOIs are validated, and then simplified as needed. The process for this is:

+
    +
  1. Validate the input AOI. If it is not valid, an error is displayed.
  2. +
  3. Merge overlapping shapes.
  4. +
  5. Convex hull.
  6. +
  7. Any out-of-range index values are handled by clamping and wrapping them to the valid range of values.
  8. +
  9. Simplify points based on proximity threshold. The target is fewer than 400 points.
  10. +
+

Each of these steps is performed only when necessary to get the AOI to a single outline with fewer than 400 points. Any unnecessary steps are skipped.

+

Examples of validation and simplification:

+
    +
  • A self-intersecting polygon is provided:
      +
    • An error is displayed.
    • +
    +
  • +
  • A single outline is provided, consisting of 1000 points:
      +
    • A simplified version of the same outline is used, consisting of fewer than 400 points.
    • +
    +
  • +
  • Multiple geometries are provided, all of them overlapping at least in part:
      +
    • A single outline is returned, representing the outline of all the shapes combined.
    • +
    +
  • +
  • Multiple geometries are provided, at least some of them entirely non-overlapping:
      +
    • A single outline is returned, representing the convex hull of all the shapes together.
    • +
    +
  • +
+

Temporal Parameters#

+
    +
  • +

    processingDate

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Limit results to records that have been processed at ASF since a given date and/or time.
    • +
    • Example:
        +
      • processingDate=2017-01-01T00:00:00UTC
      • +
      +
    • +
    +
  • +
  • +

    start

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Date of data acquisition. Can be used in combination with 'end'. You may enter natural language dates, or a date and/or time stamp. All times are in UTC. For more information on accepted date formats, see the Date Parser endpoint below.
    • +
    • Example:
        +
      • start=May+30,+2018
      • +
      • start=yesterday
      • +
      • start=2010-10-30T11:59:59Z
      • +
      • start=1+week+ago&end=now
      • +
      +
    • +
    +
  • +
  • +

    end

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Date of data acquisition. Can be used in combination with 'start'. You may enter natural language dates, or a date and/or time stamp. All times are in UTC. For more information on accepted date formats, see the Date Parser endpoint below.
    • +
    • Example:
        +
      • end=May+30,+2018
      • +
      • end=today
      • +
      • end=2021-04-30T11:59:59Z
      • +
      • start=1+week+ago&end=now
      • +
      +
    • +
    +
  • +
  • +

    season

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Start and end day of year for desired seasonal range. This keyword may be used in conjunction with start/end to specify a seasonal range within an overall date range. Values are based on the Julian calendar. You must specify both a season start and end date.
    • +
    • Example:
        +
      • season=1,31
      • +
      • season=45,67
      • +
      • season=360,10
      • +
      +
    • +
    • Values:
        +
      • 1 through 365
      • +
      +
    • +
    +
  • +
+

Results Parameters#

+
    +
  • +

    output

    +
      +
    • Desired format of the Search API results. If not specified, the default format is metalink. The preferred format is geoJSON.
    • +
    • Example:
        +
      • output=geojson
      • +
      +
    • +
    • Values:
        +
      • geojson, csv, json, kml, metalink, count, download
      • +
      +
    • +
    • Description:
        +
      • GeoJSON is the preferred output format. If a required field is not included, please contact ASF using the info below or reach the team directly at uaf-asf-discovery@alaska.edu
      • +
      • KML can be opened in Google Earth, ArcGIS Earth, or a similar program
      • +
      • Count returns the number of results returned by your query. It does not include any additional information. Using count output can be helpful in determining if your query has returned the correct number of results. There is a time limit on running Search API queries. See the Troubleshooting page for more details.
      • +
      • Metalink provides download information for the scenes returned by your query. It does not include metadata.
      • +
      • Download returns a bulk download script that includes the files returned by the search. See the Bulk Download documentation for a full guide on using the bulk download script.
      • +
      • JSON includes scene metadata and product URLs. If GeoJSON does not meet your needs, JSON is the preferred format for programmatic use.
      • +
      • CSV also includes scene metadata and product URLs. CSV returns less fields than JSON.
      • +
      +
    • +
    +
  • +
  • +

    maxResults

    +
      +
    • This keyword is also available through asf_search.
    • +
    • Maximum number of data records to return from your query.
    • +
    • Example:
        +
      • maxResults=10
      • +
      +
    • +
    +
  • +
+

Baseline Endpoint#

+

https://api.daac.asf.alaska.edu/services/search/baseline

+
    +
  • +

    reference

    +
      +
    • This is the only mandatory keyword. Input the reference scene name for which you wish to see baseline results.
    • +
    • Example:
        +
      • reference=S1B_IW_SLC__1SDV_20210704T135937_20210704T140004_027645_034CB0_4B2C
      • +
      +
    • +
    +
  • +
  • +

    processingLevel

    +
      +
    • Level to which the data has been processed. Baseline data is only available for certain processing levels.
    • +
    • Example:
        +
      • processingLevel=L1.5
      • +
      +
    • +
    • ProcessingLevel Values Which Contain Baseline Data:
        +
      • ALOS: L1.1, L1.5; default is L1.1
      • +
      • ERS-1 & ERS-2: L0, L1; default is L0
      • +
      • JERS-1: L0, L1; default is L0
      • +
      • RADARSAT-1: L0, L1; default is L0
      • +
      • Sentinel-1A & Sentinel-1B: SLC
      • +
      • Sentinel-1 Bursts: SLC
      • +
      +
    • +
    +
  • +
  • +

    output

    +
      +
    • Desired format of the Search API results. If not specified, the default format is metalink. The preferred format is geoJSON.
    • +
    • Example:
        +
      • output=geojson
      • +
      +
    • +
    • Values:
        +
      • geojson, csv, json, kml, metalink, count, download
      • +
      +
    • +
    • Description:
        +
      • GeoJSON is the preferred output format. If a required field is not included, please contact ASF using the info below or reach the team directly at uaf-asf-discovery@alaska.edu
      • +
      • KML can be opened in Google Earth, ArcGIS Earth, or a similar program
      • +
      • Count returns the number of results returned by your query. It does not include any additional information. Using count output can be helpful in determining if your query has returned the correct number of results. There is a time limit on running Search API queries. See the Troubleshooting page for more details.
      • +
      • Metalink provides download information for the scenes returned by your query. It does not include metadata.
      • +
      • Download returns a bulk download script that includes the files returned by the search. See the Bulk Download documentation for a full guide on using the bulk download script.
      • +
      • JSON includes scene metadata and product URLs. If GeoJSON does not meet your needs, JSON is the preferred format for programmatic use.
      • +
      • CSV also includes scene metadata and product URLs. CSV returns less fields than JSON.
      • +
      +
    • +
    +
  • +
  • +

    maxResults

    +
      +
    • Maximum number of data records to return from your query.
    • +
    • Example:
        +
      • maxResults=10
      • +
      +
    • +
    +
  • +
+

WKT Validation Endpoint#

+

https://api.daac.asf.alaska.edu/services/utils/wkt

+

This endpoint will validate and repair a WKT input. The repaired WKT output is how the Search API will interpret the provided WKT input. If a WKT cannot be repaired, it will return an error stating the reason. All validations and errors are returned in JSON format.

+
    +
  • wkt
      +
    • This is the only accepted keyword for this endpoint.
    • +
    • Example:
        +
      • wkt=GEOMETRYCOLLECTION(POLYGON((46 -19,30 26,-3 41,22 39,49 16,46 -19)), POLYGON((27 24,12 4,18 31,27 24)))
      • +
      • In this example, the JSON return will list the errors that were repaired, and the final wrapped and unwrapped WKT.
      • +
      +
    • +
    +
  • +
+

GeoSpatial Files to WKT Endpoint#

+

https://api.daac.asf.alaska.edu/services/utils/files_to_wkt

+

This endpoint will accept a POST request with files attached. It will return the parsed WKT from the file, as well as the repaired wrapped and unwrapped WKT. All outputs are returned in JSON format. The preferred file format is geojson, but the Search API will also support other formats, such as shapefile or kml.

+

See the Tools page for more details on POST requests.

+
    +
  • Example:
      +
    • curl -X POST -F 'files=@/path/to/file' 'https://api.aac.asf.alaska.edu/services/utils/files_to_wkt'
    • +
    +
  • +
+

Date Parser Endpoint#

+

https://api.daac.asf.alaska.edu/services/utils/date

+

This endpoint can be used to check how dates are parsed by the Search API. All parsed dates are returned in JSON format.

+
    +
  • date
      +
    • This is the only accepted keyword for this endpoint. You can use natural language, such as "yesterday", dates with or without the time stamp, or days of the week.
    • +
    +
  • +
+

Mission List Endpoint#

+

https://api.daac.asf.alaska.edu/services/utils/mission_list

+

This endpoint lists all missions (also known as campaigns or collections) for all datasets. Any of the missions returned in the list may be used as a value for the collectionName keyword in the Search endpoint. The mission list is returned in JSON format.

+
    +
  • platform
      +
    • This keyword is optional. If used, it will restrict the list of missions to the specified platform(s).
    • +
    • Remote sensing platform that acquired the data. Sentinel-1 and ERS have multiple remote sensing platforms, and you may choose whether to specify a specific platform. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • platform=ALOS
      • +
      • platform=SA,SB
      • +
      • platform=S1
      • +
      +
    • +
    • Values:
        +
      • ALOS, A3, AIRSAR, AS, ERS, ERS-1, E1, ERS-2, E2, JERS-1, J1, RADARSAT-1, R1, SEASAT, SS, S1, Sentinel, Sentinel-1, Sentinel-1A, SA, Sentinel-1B, Sentinel-1 Interferogram (BETA), SB, SMAP, SP, UAVSAR, UA
      • +
      +
    • +
    +
  • +
+

Health Endpoint#

+

https://api.daac.asf.alaska.edu/health

+

This endpoint is used to check the Search API health. It is returned in JSON format. There are no keywords associated with the health check endpoint.

+

In addition to Search API health, it also returns Search API configs and CMR health status.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/api/tools.key b/api/tools.key new file mode 100644 index 0000000..bf70464 --- /dev/null +++ b/api/tools.key @@ -0,0 +1 @@ +{{ TOOLS_1 }} \ No newline at end of file diff --git a/api/tools/index.html b/api/tools/index.html new file mode 100644 index 0000000..ac740f9 --- /dev/null +++ b/api/tools/index.html @@ -0,0 +1,1644 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Tools - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Search API Tools#

+

Searches may be executed in a variety of ways, depending on your needs. On this page, you will find syntax & character encoding tips, and further information on some of the ways to run Search API queries.

+

Syntax and Character Encoding#

+

Syntax tips

+
    +
  1. A "?" separates the endpoint URL from the keywords.
  2. +
  3. Keywords are joined by a "&". Some operating systems or programs may require a "\&"
  4. +
  5. There may not be any spaces or parentheses in the URL string. See below for how to encode these characters.
  6. +
+

Character Encoding:

+
+

space

+

replace with '%20'. Use '+' in keyword values

+

(

+

replace with '%28'

+

)

+

replace with '%29' +

+
+

For a complete list of URL codes, please see URL Encoding Reference.

+

Escaping Characters

+

If you are running Search API queries via command line, you may need to escape characters. Escaping a character tells the command line interface to interpret the character literally. Some characters that need to be escaped include spaces and ampersands (&).

+

For more information on escaping characters, please see the Bash Scripting Guide. For Windows users, more information can be found here.

+

Program Details#

+

You may use a program to assist you with Search API queries. This section will provide some details on a few of the programs you can use to write & run Search API queries and some example commands for each.

+ +

Both Wget and cURL are often installed on Linux systems. cURL is part of the Mac OS, and Wget can be installed. Microsoft Windows OS does not come with either installed, but both can be downloaded. cURL is easier to set up on a Windows machine. aria2 can be installed on Windows, Mac, or Linux systems.

+

Examples using aria2#

+

aria2c can be used to download results from the Search API with a single command. You will need to include your Earthdata username and password, all desired keywords & values, and ensure that output=metalink.

+

Aria2 — Linux/Mac Example - Download Known Scene

+
  aria2c --http-auth-challenge=true --http-user=CHANGE_ME --http-passwd='CHANGE_ME' "https://api.daac.asf.alaska.edu/services/search/param?granule_list=S1A_EW_GRDM_1SDH_20151003T040339_20151003T040443_007983_00B2A6_DDE4&output=metalink"
+
+

Aria2 — Windows Example - Download Known Scene

+
  aria2c --check-certificate=false --http-auth-challenge=true --http-user=CHANGE_ME --http-passwd="CHANGE_ME" "https://api.daac.asf.alaska.edu/services/search/param?granule_list=S1A_EW_GRDM_1SDH_20151003T040339_20151003T040443_007983_00B2A6_DDE4&output=metalink"
+
+

Aria2 — Download Based on Platform and Time-Range Search

+
  aria2c --http-auth-challenge=true --http-user=CHANGE_ME --http-passwd='CHANGE_ME' "https://api.daac.asf.alaska.edu/services/search/param?platform=Sentinel-1A&intersectsWith=point(-122.425 37.77)&start=2016-07-01T00:00:00&output=metalink"
+
+

You can store your login credentials in a config file, instead of including them in every download command.

+

aria2 - Linux/Mac Example — Create and use a configuration file

+
  echo 'http-user=CHANGE_ME' >> aria2.conf
+  echo 'http-passwd=CHANGE_ME' >> aria2.conf
+  chmod 600 aria2.conf
+
+  aria2c --conf-path=aria2.conf --http-auth-challenge=true "https://api.daac.asf.alaska.edu/services/search/param?granule_list=S1A_EW_GRDM_1SDH_20151003T040339_20151003T040443_007983_00B2A6_DDE4&output=metalink"
+
+

Additional aria2 options are available in the aria2 manual.

+

Refer to the complete documentation on configuration files for aria2.

+

Examples using Wget#

+

Once you have the download URL, you can download files individually using Wget. You can find the download URL for your desired results by first using outputs csv, json, metalink, or geojson.

+

Wget - Linux/Mac Example — Download a file

+
  wget -c --http-user=CHANGE_ME --http-password='CHANGE_ME' "https://datapool.asf.alaska.edu/GRD_MD/SA/S1A_EW_GRDM_1SDH_20151003T040339_20151003T040443_007983_00B2A6_DDE4.zip"
+
+

Wget - Windows Example — Download a file

+
  wget --check-certificate=off -c --http-user=CHANGE_ME --http-password="CHANGE_ME" "https://datapool.asf.alaska.edu/GRD_MD/SA/S1A_EW_GRDM_1SDH_20151003T040339_20151003T040443_007983_00B2A6_DDE4.zip"
+
+  wget -c --http-user=CHANGE_ME --http-password="CHANGE_ME" "https://datapool.asf.alaska.edu/GRD_MD/SA/S1A_EW_GRDM_1SDH_20151003T040339_20151003T040443_007983_00B2A6_DDE4.zip"
+
+

You can store your login credentials in a config file, instead of including them in every download command.

+

Wget - Linux/Mac Example — Create and use a configuration file

+
  echo 'http_user=CHANGE_ME' >> wget.conf
+  echo 'http_password=CHANGE_ME' >> wget.conf
+  chmod 600 wget.conf
+
+  export WGETRC="wget.conf"
+  wget -c "https://datapool.asf.alaska.edu/GRD_MD/SA/S1A_EW_GRDM_1SDH_20151003T040339_20151003T040443_007983_00B2A6_DDE4.zip"
+
+

You can also send results to a file on your PC

+

Example — query results sent to a metalink file

+
  wget -O myfilename.metalink https://api.daac.asf.alaska.edu/services/search/param?intersectsWith=point%28-119.543+37.925%29\&platform=ALOS\&output=metalink
+
+

Visualize Example - Mac/Linux

+
  wget -O myfilename.kml https://api.daac.asf.alaska.edu/services/search/param?granule_list=ALPSRP074606580,ALPSRP077086550\&output=KML
+
+

Download Example - Windows

+
  wget -c -O myfilename.metalink https://api.daac.asf.alaska.edu/services/search/param?granule_list=ALPSRP074606580,ALPSRP077086550\&output=METALINK
+
+

Additional Wget options are available in the GNU Wget Manual.

+

Refer to the complete documentation on configuration files for Wget.

+

Examples using cURL#

+

cURL - Mac/Linux Example

+
  curl https://api.daac.asf.alaska.edu/services/search/param?platform=R1\&absoluteOrbit=25234\&output=CSV
+
+

cURL - Windows Example

+

Note: Copy/pasting quotation marks sometimes causes errors. Delete and re-type the quotes after pasting.

+
  curl "https://api.daac.asf.alaska.edu/services/search/param?platform=R1&absoluteOrbit=25234&output=CSV" > myfilename.csv
+
+

You can also send results to a file on your PC

+

Mac/Linux Example — query results sent to a metalink file

+
  curl https://api.daac.asf.alaska.edu/services/search/param?granule_list=ALPSRP074606580,ALPSRP021910740,ALPSRP085800750 >myfilename.metalink
+
+

Windows Example — query results sent to a metalink file

+
  curl "https://api.daac.asf.alaska.edu/services/search/param?granule_list=ALPSRP074606580,ALPSRP021910740,ALPSRP085800750" > myfilename.metalink
+
+

Search Example - Mac/Linux

+
  curl https://api.daac.asf.alaska.edu/services/search/param?platform=r1\&asfframe=300\&output=CSV > myfilename.csv
+
+

Search Example - Windows

+
  curl  "https://api.daac.asf.alaska.edu/services/search/param?platform=r1&asfframe=300&output=CSV" > myfilename.csv
+
+

Visualize Example - Windows

+
  curl "https://api.daac.asf.alaska.edu/services/search/param?granule_list=ALPSRP074606580,ALPSRP077086550&output=KML" >myfilename.kml
+
+

Download Example - Windows

+
  curl -L "https://api.daac.asf.alaska.edu/services/search/param?granule_list=ALPSRP074606580,ALPSRP077086550&output=METALINK" >myfilename.metalink
+
+

POST Requests#

+

Some keywords and endpoints will accept a POST request. The POST examples below are using cURL.

+

POST Example - WKT output from file

+
  curl -X POST -F 'files=@/path/to/file.geojson' 'https://api.daac.asf.alaska.edu/services/utils/files_to_wkt'
+
+

POST Examples - intersectsWith Keyword

+
  curl -X POST -F 'intersectsWith=LINESTRING(-97.1191 26.4312,-95.5371 29.1522,-83.7598 29.993,-81.5625 25.4036)' 'https://api.daac.asf.alaska.edu/services/search/param'
+
+

You can add additional parameters to your POST request with the -F argument for each desired parameter.

+
  curl -X POST -F 'platform=S1' -F 'output=geojson' -F 'maxresults=10' -F 'intersectsWith=POINT(-102.4805 38.7541)' 'https://api.daac.asf.alaska.edu/services/search/param'
+
+

For further reading, see POST requests

+

Web Browser#

+

You may run the Search API queries directly in a web browser of your choice. Simply copy and paste the query into a web browser. Any errors will be returned in JSON format.

+

You will need to use URL encoding for spaces and parentheses. Please refer to the Character Encoding section or see URL Encoding Reference for more details.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/api/troubleshooting.key b/api/troubleshooting.key new file mode 100644 index 0000000..bb06495 --- /dev/null +++ b/api/troubleshooting.key @@ -0,0 +1 @@ +{{ TROUBLESHOOTING_1 }} \ No newline at end of file diff --git a/api/troubleshooting/index.html b/api/troubleshooting/index.html new file mode 100644 index 0000000..bfaaea8 --- /dev/null +++ b/api/troubleshooting/index.html @@ -0,0 +1,1439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Troubleshooting - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Search API Troubleshooting#

+

If you are troubleshooting Search API queries, consider using asf_search. asf_search is a Python package for performing searches of the ASF catalog. More information can be found here.

+

Trouble Area: Query returns HTTP 429 with error message

+
    +
  • Reason: Query returns HTTP 429 with error message "Rate limited, please reduce your request rate to 250/minute or less"
  • +
  • Remedy: There is a rate limitation on the search endpoint. Refer to Rate limitations for tips on how to construct your queries.
  • +
+

Trouble Area: Windows cURL “unrecognized protocol”

+
    +
  • Reason: Invisible double quotes inserted when copy/pasting examples
  • +
  • Remedy: Delete the visible quotes, which will delete the invisible quotes. Then retype quotes.
  • +
+

Trouble Area: Download fails with “401 Unauthorized” or “Authorization failed”

+
    +
  • Reason: Missing or invalid Earthdata username/password
  • +
  • Remedy: Check that you are correctly including your Earthdata username and password in your download command or config file.
  • +
+

Trouble Area: Download fails with “401 Unauthorized” or “Authorization failed”

+
    +
  • Reason: Special characters in Earthdata password
  • +
  • Remedy: Passwords with special characters will need to be inside quotes.
  • +
+

Trouble Area: Can’t authenticate

+
    +
  • Reason: Missing study area or EULA
  • +
  • Remedy: Log in to Earthdata and ensure your study area is set, and you have agreed to all necessary End-User License Agreements.
  • +
+

Trouble Area: Search API request with ‘+’ in it fails

+
    +
  • Reason: Some keyword values could contain spaces.
  • +
  • Remedy: Try replacing the ‘+’ with ‘%2B’. For further details, refer to Character Encoding on the Tools page.
  • +
+

Trouble Area: Search API request fails

+
    +
  • Reason: https is required
  • +
  • Remedy: Make sure you are using https, not http.
  • +
+

Trouble Area: Search API request hangs, fails, or returns an error

+
    +
  • Reason: Your URL may include spaces or special characters.
  • +
  • Remedy: Refer to Character Encoding on the Tools page and ensure you are encoding spaces and special characters correctly.
  • +
+

Trouble Area: Search API returns Validation Error

+
    +
  • Reason: The reason for the validation error is included in the returned error message.
  • +
  • Remedy: Refine your keywords and values as needed. If you are unsure why you received the validation error, you may contact ASF using the info below.
  • +
+

Trouble Area: Search API query does not return expected number of results

+
    +
  • Reason: There is a 15 minute time limit on running Search API queries.
  • +
  • Remedy: First, try the same query with "output=count". If the count is high, consider narrowing your search by using more keywords, or by using keyword “maxResults” to limit it. You may also try shortening the date range to split your search into a series of smaller searches.
  • +
+

Trouble Area: Search API query with "product_list" keyword returns no results

+
    +
  • Reason: Other keywords may be competing with the product_list value(s).
  • +
  • Remedy: Try removing other keywords from your query. You may also try "output=count" to see how many results your query should return.
  • +
+

Trouble Area: Selected output format does not include needed fields

+
    +
  • Reason: Some output formats include different fields.
  • +
  • Remedy: GeoJSON is the preferred default format. If a required field is not included, please contact ASF using the info below or reach the team directly at uaf-asf-discovery@alaska.edu
  • +
+ + + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asf_search/ASFProduct.key b/asf_search/ASFProduct.key new file mode 100644 index 0000000..ebf38ea --- /dev/null +++ b/asf_search/ASFProduct.key @@ -0,0 +1 @@ +{{ ASFPRODUCT_1 }} \ No newline at end of file diff --git a/asf_search/ASFProduct/index.html b/asf_search/ASFProduct/index.html new file mode 100644 index 0000000..5abdaf0 --- /dev/null +++ b/asf_search/ASFProduct/index.html @@ -0,0 +1,1635 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ASFProduct - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

ASFProduct#

+

Description#

+

This class describes a single product from the ASF archive. The class provides metadata, as well as several helpful methods for interacting with the product.

+
+

Attributes#

+
    +
  • properties (dict): Provides product metadata such as Beam Mode, Start Time, etc.
  • +
  • geometry (dict): Describes the product's physical extents as a geojson snippet.
  • +
  • baseline dict: The product's baseline related fields, if available in CMR.
  • +
  • umm (dict): the raw umm json response from CMR used to populate properties, geometry, baseline, and meta.
  • +
  • meta (dict): the metadata json returned from CMR.
  • +
+ + +
+

Methods#

+

geojson()#

+

ASFProduct.__str__() utilizes this method for serialization via json.dumps()

+

args: +None

+

returns:

+
    +
  • dict describing the product as a geojson snippet.
  • +
+
+

download(path, filename=None, session=None)#

+

Downloads this product to the specified path and optional filename.

+

args:

+
    +
  • path: The directory into which this product should be downloaded.
  • +
  • filename (optional): Filename to use instead of the original filename of this product.
  • +
  • session (optional): The session to use, in most cases should be authenticated beforehand. If no session is provided, a blank (unauthenticated) session will be used.
  • +
  • fileType (optional): Used to download Burst XML metadata. Specify fileType=asf.FileDownloadType.ADDITIONAL_FILES to download the XML metadata. To download both .tiff and .xml files for bursts, use asf.FileDownloadType.ALL_FILES
      +
    • Example: burst_results.download(session=session, path="./", fileType=asf.FileDownloadType.ADDITIONAL_FILES)
    • +
    • Note: The Burst XML Metadata is a virtually generated file, and therefore does not have its own unique filename. The XML Metadata can only be found via the burst scene name.
    • +
    +
  • +
+

returns: +None

+
+

stack()#

+

Builds a baseline stack using this product as a reference

+

args:

+
    +
  • cmr_provider (optional): Custom provider name to constrain CMR results to, for more info on how this is used, see CMR documentation
  • +
  • session (optional): A Session to be used when performing the search. For most uses, can be ignored. Used when searching for a dataset, provider, etc. that requires authentication. See ASFSession for more details.
  • +
  • host (optional): SearchAPI host, defaults to Production SearchAPI. This option is intended for dev/test purposes and can generally be ignored.
  • +
+

returns:

+
    +
  • ASFSearchResults representation of the stack, with the addition of baseline values (temporal, perpendicular) attached to each ASFProduct
  • +
+
+

get_stack_opts()#

+

Builds search options that describe an InSAR stack based on this product. Similar to stack() but doesn't perform the search, simply returns ASFSearchOptions which can be inspected or adjusted and then passed to various search functions.

+

args: +None

+

returns:

+
    +
  • ASFSearchOptions object
  • +
+
+

centroid()#

+

Determines the centroid of a product.

+

args: +None

+

returns:

+
    +
  • shapely.geometry.point.Point object describing the centroid of the product
  • +
+ + +

remotezip()#

+

Returns a configured RemoteZip object, which allows downloading selected parts of a product's zip archive. +For more information on how to use remotezip with asf-search, see the Downloading Single Products section of the example jupyter notebook. For more information on the open-source remotezip package, check out the remotezip project repo.

+

args:

+
    +
  • session ASFSession: An authenticated ASFSession object that will be used to download the product
  • +
+

returns:

+
    +
  • remotezip.RemoteZip object authenticated with the passed ASFSession object
  • +
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asf_search/ASFSearchOptions.key b/asf_search/ASFSearchOptions.key new file mode 100644 index 0000000..b574f79 --- /dev/null +++ b/asf_search/ASFSearchOptions.key @@ -0,0 +1 @@ +{{ ASFSOPS_1 }} \ No newline at end of file diff --git a/asf_search/ASFSearchOptions/index.html b/asf_search/ASFSearchOptions/index.html new file mode 100644 index 0000000..7aef888 --- /dev/null +++ b/asf_search/ASFSearchOptions/index.html @@ -0,0 +1,1606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ASFSearchOptions - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

ASFSearchOptions#

+

Description#

+

This class describes a set of search parameters. While it is not required to use this class when constructing a search, it can be useful, as it provides some degree of immediate parameter validation, as well as a convenient way to manipulate and handle search options in general.

+

Specific search parameters are handled as object attributes. Attempting to add an attribute that is not supported will raise a KeyError. Attempting to delete an attribute will result in it being set to None. Search parameters can be set via kwargs at object instantion, or directly on an existing object using the normal mechanisms.

+

Converting to a dict will only include search options which have actually been set to a usable value. That is, any options set to None will be ignored.

+
+

Attributes#

+
    +
  • maxResults
  • +
  • absoluteBurstID
  • +
  • absoluteOrbit
  • +
  • asfFrame
  • +
  • beamMode
  • +
  • provider
  • +
  • collectionName
  • +
  • maxDoppler
  • +
  • minDoppler
  • +
  • maxFaradayRotation
  • +
  • minFaradayRotation
  • +
  • flightDirection
  • +
  • flightLine
  • +
  • fullBurstID
  • +
  • frame
  • +
  • granule_list
  • +
  • product_list
  • +
  • intersectsWith
  • +
  • lookDirection
  • +
  • offNadirAngle
  • +
  • operaBurstID
  • +
  • platform
  • +
  • polarization
  • +
  • processingLevel
  • +
  • relativeBurstID
  • +
  • relativeOrbit
  • +
  • processingDate
  • +
  • start
  • +
  • end
  • +
  • season
  • +
  • groupID
  • +
  • insarStackId
  • +
  • instrument
  • +
  • session
  • +
+
+

Methods#

+

ASFSearchOptions does not provide any methods intended for direct use, instead relying on a handful of dunders for the desired behavior. For clarity, these are included below.

+

init()#

+

Establishes the various attributes described above and processes any kwargs into them.

+

args:

+
    +
  • **kwargs, limited to names listed as attributes above. Anything else will raise a KeyError
  • +
+

returns: +None

+
+

setattr()#

+

Sets the attribute named by key to the specified value after passing it through an appropriate validator function.

+

Values of None are allowed as a way to un-set the attribute. Attempting to set a key not listed in the above attribute list will raise a KeyError

+

args:

+
    +
  • key: the name of the attribute to set
  • +
  • value: the value to which the named attribute should be set
  • +
+

returns: +None

+
+

delattr()#

+

Clears an attribute names by item by way of setting it to None

+

args:

+
    +
  • item: the name of the attribute to be cleared
  • +
+

returns: +None

+
+

iter()#

+

Used when converting the ASFSearchOptions object to more fundamental objects, such as dict

+

Only includes attributes that are not None.

+

args: +None

+

yields:

+
    +
  • (key, value) pairs for each of the above attributes that are not None
  • +
+
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asf_search/ASFSearchResults.key b/asf_search/ASFSearchResults.key new file mode 100644 index 0000000..e66c55e --- /dev/null +++ b/asf_search/ASFSearchResults.key @@ -0,0 +1 @@ +{{ ASFSS_1 }} \ No newline at end of file diff --git a/asf_search/ASFSearchResults/index.html b/asf_search/ASFSearchResults/index.html new file mode 100644 index 0000000..10cae2c --- /dev/null +++ b/asf_search/ASFSearchResults/index.html @@ -0,0 +1,1611 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ASFSearchResults - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

ASFSearchResults#

+

Description#

+

This class describes a set of search results from the ASF archive. The class provides a convenient way to manage and examine search results, as well as export and download functionality.

+
+

Attributes#

+
    +
  • searchOptions (ASFSearchOptions): The search options used to generate this set of results. May be None in some cases.
  • +
  • searchComplete (bool): Flag signifying asf_search.search() sucessfully completed gathering results from CMR.
  • +
+
+

Methods#

+

download()#

+

Iterates over each ASFProduct and downloads them to the specified path.

+

args:

+
    +
  • path: The directory into which the products should be downloaded.
  • +
  • session: The session to use, in most cases should be authenticated beforehand.
  • +
  • processes: Number of download processes to use. Defaults to 1 (i.e. sequential download)
  • +
  • fileType (optional): Used to download Burst XML metadata. Specify fileType=asf.FileDownloadType.ADDITIONAL_FILES to download the XML metadata. To download both .tiff and .xml files for bursts, use asf.FileDownloadType.ALL_FILES
      +
    • Example: burst_results.download(session=session, path="./", fileType=asf.FileDownloadType.ADDITIONAL_FILES)
    • +
    • Note: The Burst XML Metadata is a virtually generated file, and therefore does not have its own unique filename. The XML Metadata can only be found via the burst scene name.
    • +
    +
  • +
+

returns: None

+
+

geojson()#

+

ASFSearchResults.__str__() utilizes this method for serialization via json.dumps()

+

args: None

+

returns:

+
    +
  • dict describing the search results as a geojson object.
  • +
+

csv()#

+

Creates a csv formatted string generator from the results

+

args: None

+

returns:

+
    +
  • A csv formatted string generator
  • +
+

kml()#

+

Creates a kml formatted string generator from the results

+

args: None

+

returns:

+
    +
  • A kml formatted string generator
  • +
+ +

Creates a metalink formatted string generator from the results

+

args: None

+

returns:

+
    +
  • A metalink formatted string generator
  • +
+

raise_if_incomplete()#

+

Use to check if results returned from asf_search.search() are incomplete (this can happen +if an error occurs while querying CMR)

+

args: None

+

raises:

+
    +
  • Raises an asf_search.exceptions.ASFSearchError if the results are incomplete
  • +
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asf_search/ASFSession.key b/asf_search/ASFSession.key new file mode 100644 index 0000000..7831c2c --- /dev/null +++ b/asf_search/ASFSession.key @@ -0,0 +1 @@ +{{ ASFSESSION_1 }} \ No newline at end of file diff --git a/asf_search/ASFSession/index.html b/asf_search/ASFSession/index.html new file mode 100644 index 0000000..fb0278b --- /dev/null +++ b/asf_search/ASFSession/index.html @@ -0,0 +1,1531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ASFSession - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

ASFSession#

+

Description#

+

This class extends requests.session to provide convenient ASF-specific authorization options. ASFSession is a subclass of Session. More information can be found here

+
+

Methods#

+

auth_with_creds()#

+

Authenticates the session (self) using Earthdata Login username/password credentials.

+

args:

+ +

returns:

+
    +
  • returns self for convenience
  • +
+
+

auth_with_token()#

+

Authenticates the session (self) using an Earthdata Login Authorization: Bearer token.

+

args:

+ +

returns:

+
    +
  • returns self for convenience
  • +
+
+

auth_with_cookiejar()#

+

Authenticates the session (self) using a pre-existing cookiejar.

+

args:

+
    +
  • cookies: An http.cookiejar compatible object
  • +
+

returns:

+
    +
  • returns self for convenience
  • +
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asf_search/BestPractices.key b/asf_search/BestPractices.key new file mode 100644 index 0000000..0bb1bfb --- /dev/null +++ b/asf_search/BestPractices.key @@ -0,0 +1 @@ + {{ BEST_PRACTICES }} \ No newline at end of file diff --git a/asf_search/BestPractices/index.html b/asf_search/BestPractices/index.html new file mode 100644 index 0000000..ece36a4 --- /dev/null +++ b/asf_search/BestPractices/index.html @@ -0,0 +1,2273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Best Practices - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

asf_search Best Practices#

+

In addition to covering best practices, this page also contains advanced search techniques and serves as the "philosophy of asf_search".

+

Topics covered include:

+
    +
  • General recommendations, including +working with results, performance, common search filters and types, and count
  • +
  • Specifics for some datasets
  • +
  • Granule and product searches and the preferred method for these
  • +
  • Secondary searches such as stacking
  • +
  • Download and recommended authentication method
  • +
  • Advanced search techniques, including ranges, subclasses, large result sets, and more
  • +
+

General Recommendations#

+

This section contains information on result sets, general performance, the different search types available, common filter examples, and count.

+

Result Sets#

+

Search results are returned as an ASFSearchResults object, a sublass of User List, containing a list of ASFProduct objects. Each of these classes provides some additional functionality to aid in working with the results and individual products. +ASFProduct provides a number of metadata fields, such as:

+
    +
  • Geographic coordinates
  • +
  • Latitude/Longitude
  • +
  • Shape type
  • +
  • Scene and product metadata
  • +
  • Path, frame
  • +
  • Platform, beam, polarization
  • +
  • File name, size, URL
  • +
+

Geographic coordinates are stored in the geometry attribute:

+

results[0].geometry

+

Other metadata is available through the properties attribute:

+

results[0].properties

+

ASFProduct objects provides geojson-based serialization, in the form of a geojson feature snippet:

+

print(results[0])

+

ASFSearchResults also supports the following output formats:

+
    +
  • csv
  • +
  • jsonlite
  • +
  • jsonlite2
  • +
  • metalink
  • +
  • kml
  • +
+

General performance#

+

When searching for multiple products it's faster to search all products at once in a single search, rather than running a separate query for each product, which involves multiple https requests.

+
import asf_search as asf
+
+granules = ['S1B_IW_GRDH_1SDV_20161124T032008_20161124T032033_003095_005430_9906', 'S1-GUNW-D-R-087-tops-20190301_20190223-161540-20645N_18637N-PP-7a85-v2_0_1', 'ALPSRP111041130']
+
+# THIS IS SLOW AND MAKES MORE NETWORK REQUESTS THAN NECESSARY
+batched_results = ASFSearchResults([])
+for granule in granules:
+    unbatched_response = asf.granule_search(granules_list=granule)
+    batched_results.extend(batched_results)
+
+# THIS WILL ALWAYS BE FASTER
+fast_results = asf.granule_search(granules_list=granules)
+
+

If you need to perform intermediate operations on large results (such as writing metadata to a file or calling some external process on results), use the search_generator() method to operate on results as they're returned page-by-page (default page size is 250).

+
import asf_search as asf
+
+opts = asf.ASFSearchOptions(platform=asf.DATASET.SENTINEL1, maxResults=1000)
+
+for page in asf.search_generator(opts=opts):
+    foo(page)
+
+

Differences between search types#

+

To see details on different search types, see the Searching section.

+

Common Filters#

+

Search options can be specified using kwargs, which also allows them to be handled using a dictionary:

+
opts = {
+    'platform': asf.PLATFORM.ALOS,
+    'start': '2010-01-01T00:00:00Z',
+    'end': '2010-02-01T23:59:59Z'
+}
+
+

Below are some common filter examples:

+
results = asf.geo_search(
+    intersectsWith='POLYGON((-91.97 28.78,-88.85 28.78,-88.85 30.31,-91.97 30.31,-91.97 28.78))',
+    platform=asf.PLATFORM.UAVSAR,
+    processingLevel=asf.PRODUCT_TYPE.METADATA,
+    maxResults=250)
+
+

search_count()#

+

You may use the search_count() method to return the count of total results matching the passed search options.

+

This example returns the current size of the SENTINEL1 catalog:

+
opts = {
+'platform': asf.PLATFORM.SENTINEL1}
+count = asf.search_count(**opts)
+
+

Dataset Specifics#

+

Constants are provided for each dataset. The list of constants can be found here.

+

Basic dataset search example:

+
sentinel_results = asf.search(dataset=asf.DATASET.SENTINEL1, maxResults=250)
+
+

You can view the metadata for your results via the properties dictionary:

+
sentinel_results[0].properties
+
+

Or you can view the metadata as a geojson formatted dictionary:

+
sentinel_results.geojson()
+
+

NISAR#

+

asf_search supports searching for lists of short names by the shortName keyword. +The currently available NISAR data that CMR provides lacks searchable additional attributes. +Therefore, the best way to search for NISAR results is via combinations of shortName, dataset, platform, and granule_list/product_list keywords.

+

NISAR example:

+
nisar_gslc_gunw = asf.search(shortName=['NISAR_L2_GSLC_V1', 'NISAR_L2_GUNW_V1'], opts=search_opts, maxResults=250)
+print(nisar_gslc_gunw)
+
+

Opera-S1#

+

The Opera dataset has both standard products and CalVal (calibration/validation) products available. +Please note that the CalVal products are treated as their own dataset in asf_search. +Both can be found in the constants list.

+

SLC-Burst#

+

The SLC Burst dataset has both tiff and xml data associated with a single entry in CMR. To access the xml data, +see the section on downloading additional files.

+

fullBurstID, relativeBurstID, and absoluteBurstID are SLC Burst specific filters. To +get a temporal stack of products over a single burst frame, use fullBurstID, which is shared between +all bursts over a single frame.

+

Further Reading#

+

For more information on the constants and keywords available, see the Keywords section.

+

Search Specifics#

+

This section contains information on granule and product searches, secondary searches, + and other search details.

+ +

granule_search() and product_search() are similar. +Granule (also called a scene) searches include all files types for the specified granule, whereas product searches specify one file type. +Granule searches can be 1:many, whereas a product search will always be 1:1.

+

Granule search example:

+
granule_list = [
+    'S1B_IW_GRDH_1SDV_20190822T151551_20190822T151616_017700_0214D2_6084',
+    'S1B_IW_GRDH_1SDV_20190810T151550_20190810T151615_017525_020F5A_2F74',
+    'S1B_IW_GRDH_1SDV_20190729T151549_20190729T151614_017350_020A0A_C3E2',
+    'S1B_IW_GRDH_1SDV_20190717T151548_20190717T151613_017175_0204EA_4181',
+    'S1B_IW_GRDH_1SDV_20190705T151548_20190705T151613_017000_01FFC4_24EC',
+    'S1B_IW_GRDH_1SDV_20190623T151547_20190623T151612_016825_01FA95_14B9',
+    'S1B_IW_GRDH_1SDV_20190611T151546_20190611T151611_016650_01F566_D7CE',
+    'S1B_IW_GRDH_1SDV_20190530T151546_20190530T151611_016475_01F02E_BF97',
+    'S1B_IW_GRDH_1SDV_20190518T151545_20190518T151610_016300_01EAD8_9308',
+    'S1B_IW_GRDH_1SDV_20190506T151544_20190506T151609_016125_01E56C_1D67'
+]
+results = asf.granule_search(granule_list)
+print(results)
+
+

Product search example:

+
product_list = [
+    'S1A_IW_GRDH_1SDV_20190809T001336_20190809T001401_028485_033839_78A1-GRD_HD',
+    'S1A_IW_GRDH_1SDV_20150322T000454_20150322T000524_005137_006794_56E3-GRD_HD',
+    'S1A_IW_GRDH_1SDV_20160121T001256_20160121T001321_009585_00DF26_5B84-GRD_HD',
+    'S1A_IW_GRDH_1SDV_20151117T000448_20151117T000513_008637_00C455_3DC2-GRD_HD'
+]
+results = asf.product_search(product_list)
+print(results)
+
+

granule_search() and product_search() do not make use of any other search filters, but will accept kwargs for consistency with other search functions:

+
results = asf.granule_search(granule_list=granule_list)
+print(f'{len(results)} results found')
+
+

Note about incorrect methods#

+

It is generally preferred to "collapse" many small queries into fewer large queries. That is, it may be easy and logically reasonable to run a number of small granule_search() queries via a foreach loop over each of the items in the original granule list. Please do not do this. It consumes a lot of resources at both ASF and at CMR.

+

Instead, combine your small queries into a single large query where possible, as shown above, and then post-process the results locally. granule_search() and product_search() can support very large lists, and will break them up internally when needed.

+

frame vs asfframe#

+

When using the frame keyword with certain platforms/datasets, asf_search will implicitly swap to using the asfframe keyword instead at search time. The platforms/datasets this affects are:

+
    +
  • SENTINEL-1A/B
  • +
  • ALOS
  • +
+

In the query to CMR, this means searching by the FRAME_NUMBER instead of the CENTER_ESA_FRAME additional attribute. +A way to avoid this on searches and use CENTER_ESA_FRAME with the above platforms/datasets is to use cmr_keywords:

+

asf.search(platform=asf.PLATFORM.SENTINEL1, cmr_keywords=[('attribute[]', 'int,CENTER_ESA_FRAME,1001')], maxResults=250)

+

Stacking#

+

Once you have identified a result set or a product id, you may wish to build a baseline stack based on those results. +You may use either the stack() or stack_from_id() methods to accomplish this.

+

stack_from_id() is provided largely as a convenience: internally, it performs a product_search() using the provided ID, and then returns the results of that product's stack() method. +For this reason, it is recommended that if you have an ASFProduct object at hand, you use that to build your stack directly, as it removes the need for the additional search action. +For other cases where you have parameters describing your reference scene but not an ASFProduct object itself, it is appropriate to use one of the various search features available to obtain an ASFProduct first.

+

A basic example using ASFProduct.stack():

+
import asf_search as asf
+
+reference = asf.product_search('S1A_IW_SLC__1SDV_20220215T225119_20220215T225146_041930_04FE2E_9252-SLC')[0]
+
+print(reference.stack())
+
+

The results are a standard ASFSearchResults object containing a list of ASFProduct objects, each with all the usual functionality. +There are 2 additional fields in the ASFProduct objects: temporalBaseline and perpendicularBaseline. +temporalBaseline describes the temporal offset in days from the reference scene used to build the stack. +perpendicularBaseline describes the perpendicular offset in meters from the reference scene used the build the stack. +The reference scene is included in the stack and will always have a temporal and perpendicular baseline of 0.

+

Platform vs Dataset#

+

asf_search provides 2 major keywords with subtle differences:

+
    +
  • platform
  • +
  • dataset
  • +
+

platform maps to the platform[] CMR keyword; values like Sentinel-1A, UAVSAR, ALOS. A limitation of searching by +platform is that for platforms like Sentinel-1A there are a lot of Sentinel-1 derived product types (OPERA-S1, SLC-BURST). +For every SLC product, there are 27 additional OPERA-S1 and SLC-BURST products, which can lead to homogeneous results depending on your search filters.

+

The dataset keyword serves as a solution for this. Each "dataset" is a collection of concept ids generally associated with commonly used datasets.

+
# At the time of writing will likely contain mostly `OPERA-S1` and/or `SLC-BURST` products
+platform_results = asf.search(dataset=asf.PLATFORM.SENTINEL1, maxResults=250) 
+
+# Will contain everything but `OPERA-S1` and/or `SLC-BURST` products
+dataset_results = asf.search(dataset=asf.DATASET.SENTINEL1, maxResults=250)
+
+# Will contain OPERA-S1 Products
+opera_results = asf.search(dataset=asf.DATASET.OPERA_S1, maxResults=250)
+
+# Will contain SLC-BURST products
+slc_burst_results = asf.search(dataset=asf.DATASET.SLC_BURST, maxResults=250)
+
+

CMR UAT Host#

+

asf_search defaults to querying against the production CMR API, cmr.earthdata.nasa.gov. +In order to use another CMR host, set the host keyword with ASFSearchOptions.

+
uat_opts = asf.ASFSearchOptions(host='cmr.uat.earthdata.nasa.gov', maxResults=250)
+uat_results = asf.search(opts=uat_opts)
+
+

Campaign lists#

+

asf_search provides a built in method for searching for campaigns via platform.

+

asf.campaigns(platform=asf.PLATFORM.SENTINEL1A)

+

CMR Keyword Aliasing#

+

asf_search aliases the following keywords behind the scenes with corresponding collection concept ids for improved search performance:

+
    +
  • platform
  • +
  • processingLevel
  • +
+

The Alias lists are updated as needed with each release, but if you're not finding expected results, then the alias list may be out of date. +In order to skip the aliasing step, set the collectionAlias keyword to false with ASFSearchOptions

+
opts = asf.ASFSearchOptions(collectionAlias=False, maxResults=250)
+unaliased_results = asf.search(opts=opts)
+
+

Please note, this will result in slower average search times. If there are any results missing from new datasets, please report it as an issue in github with the concept id and name of the collection missing from the dataset.

+

Download#

+

This Jupyter notebook covers the available authentication methods. +Once authenticated, it provides a workflow for downloading search results.

+ +

Using .netrc credentials is the preferred method for authentication. +This guide will show you how to set up a .netrc file. +Requests will attempt to get the authentication credentials for the URL’s hostname from your .netrc file. +The .netrc file overrides raw HTTP authentication headers set with headers=. +If credentials for the hostname are found, the request is sent with HTTP Basic Auth.

+

Advanced Search Techniques#

+

Below you will find recommendations for advanced search techniques, such as subclassing, authentication, and the preferred method for large searches.

+

Sentinel-1 and GroupID#

+

Sentinel-1 products as well as most Sentinel-1 derived datasets (OPERA-S1, SLC-Burst) have a group id associated with them. +This means that getting the original source scene, or any product associated with that scene, is as simple as using the groupID +keyword in a search.

+
import asf_search as asf
+
+burst_name = 'S1_279916_IW1_20230418T162849_VV_A7E1-BURST'
+burst_granule = asf.search(granule_list=['S1_279916_IW1_20230418T162849_VV_A7E1-BURST'])[0]
+
+groupID = burst_granule.properties['groupID']
+
+# gets the parent SLC of the burst product
+parent_slc = asf.search(groupID=groupID, processingLevel=asf.PRODUCT_TYPE.SLC)[0]
+
+# gets all other SLC Bursts associated with the same parent SLC
+bursts_in_same_scene = asf.search(groupID=groupID, processingLevel=asf.PRODUCT_TYPE.BURST)
+
+# gets ALL Sentinel-1 products and derived products available for the parent scene
+all_products_for_scene = asf.search(groupID=groupID)
+
+

Subclassing#

+

ASFProduct is the base class for all search result objects. +There are several subclasses of ASFProduct that are used for specific platforms and product types with unique properties/functionality.

+

Key Methods:

+
    +
  • geojson()
  • +
  • download()
  • +
  • stack()
  • +
  • get_stack_opts() (returns None in ASFProduct, implemented by ASFStackableProduct subclass and its subclasses)
  • +
  • centroid()
  • +
  • remotezip() (requires optional dependency to be installed)
  • +
  • get_property_paths() (gets product's keywords and their paths in umm dictionary)
  • +
  • translate_product() (reads properties from umm, populates properties with associated keyword)
  • +
  • get_sort_keys()
  • +
  • umm_get()
  • +
+

Key Properties:

+
    +
  • properties
  • +
  • _base_properties (what get_property_paths() uses to find values in umm JSON properties)
  • +
  • umm (the product's umm JSON from CMR)
  • +
  • metadata (the product's metadata JSON from CMR)
  • +
+

ASFStackableProduct is an important ASFProduct subclass, from which stackable product types meant for time series analysis are derived. +ASFStackableProduct has a class enum, BaselineCalcType, that determines how perpendicular stack calculations are handled. +Each subclass keeps track of their baseline calculation type via the baseline_type property.

+

Inherits: ASFProduct

+

Inherited By: ALOSProduct; ERSProduct; JERSProduct; RADARSATProduct; S1Product; +S1BurstProduct; OPERAS1Product, ARIAS1GUNWProduct

+

Key Methods:

+
    +
  • get_baseline_calc_properties()
  • +
  • get_stack_opts() (overrides ASFproduct)
  • +
  • is_valid_reference()
  • +
  • get_default_baseline_product_type()
  • +
+

Key Definitions for class enum BaselineCalcType:

+
    +
  • PRE_CALCULATED: has pre-calculated insarBaseline value that will be used for perpendicular calculations
  • +
  • CALCULATED: uses position/velocity state vectors and ascending node time for perpendicular calculations
  • +
+

Key Fields:

+
    +
  • baseline
  • +
  • baseline_type (BaselineCalcType.PRE_CALCULATED by default or BaselineCalcType.CALCULATED)
  • +
+

Because ASFProduct is built for subclassing, that means you can provide your own custom subclasses derived directly from ASFProduct or even from a pre-existing subclass like S1Product or OperaS1Product.

+

For more information on subclassing, see the Jupyter notebook.

+

Using authenticated searches#

+

Downloading data, and accessing some data, requires an authenticated session with Earthdata Login. +To simplify this workflow, the ASFSession class is provided.

+
auth_with_creds()
+auth_with_token()
+auth_with_cookiejar()
+
+

Creating an authenticated session example:

+
from getpass import getpass
+session = asf.ASFSession()
+session.auth_with_creds(input('EDL Username'), getpass('EDL Password'))
+
+

The ASFSearchOptions class is provided for storing and validating search parameters. +Creating an ASFSearchOptions object is required to pass our authenticated session to search().

+
search_opts = asf.ASFSearchOptions(
+dataset=asf.DATASET.NISAR,
+session=session)
+
+nisar_response = asf.search(opts=search_opts, maxResults=250)
+
+

search_generator() for large result sets#

+

The recommended way to perform large, long-running searches is to use search_generator() to yield CMR results page by page. +This allows you to stream results to a file in the event CMR times out. +Different output formats can be used.

+

Note that asf_search queries CMR with page sizes of 250, so setting maxResults=500 means asf_search will have to query CMR twice, each time returning 250 products:

+

large_results_generator = asf.search_generator(maxResults=500, platform=asf.PLATFORM.SENTINEL1A)

+
with open("search_results.metalink", "w") as f:
+    f.writelines(asf.export.results_to_metalink(large_results_generator))
+
+

Another usage example:

+
import asf_search as asf
+opts = asf.ASFSearchOptions(shortName='ARIA_S1_GUNW')
+urs = []
+for page in asf.search_generator(opts=opts):
+    urs.extend(product.properties['fileID'] for product in page)
+    print(len(urs))
+
+

Downloading additional files#

+

Some product types, such as SLC Bursts or Opera-S1 products, have several files that can be downloaded. +We can specify which files to download by setting the fileType and using the FileDownloadType enum class.

+

Additional files are stored in this array:

+
product.properties['additionalUrls']
+
+

To download only the additional files:

+
FileDownloadType.ADDITIONAL_FILES    # everything in 'additionalUrls'
+
+

To download the default file:

+
FileDownloadType.DEFAULT_FILE        # The default data file, 'url'
+
+

To download both:

+
FileDownloadType.ALL_FILES           # all of the above
+
+

This example will download all additional files under the additionalUrls attribute:

+
cslc_results[0].download(session=session, path = './', fileType=asf.FileDownloadType.ADDITIONAL_FILES)
+
+

To be more specific, we can use the download_urls() or download_url() methods

+
print(f"Additional urls: {opera_results[0].properties['additionalUrls']}")
+
+url = opera_results[0].properties['additionalUrls'][0]
+fileName = url.split('/')[-1]
+
+asf.download_url(url, session=session, path ='./', filename=fileName)
+
+

S3 URIs#

+

Some product types (Sentinel-1, BURST, OPERA, NISAR) have s3 direct access URIs available. They are accessible under the s3Urls properties key:

+

ASFProduct.properties['s3Urls'].

+

CMR Keywords Search Parameter#

+

You can also search for granules using readable_granule_name via pattern matching.

+

To do this, you can pass the CMR search keyword config directly with the cmr_keywords search parameter. +This allows you to pass any valid CMR keyword-value pair that isn't covered by asf_search directly, as well as configure existing parameter behavior.

+

More info on pattern matching and parameter options can be found here.

+

Example:

+
gslc_results = asf.search(granule_list=['*046_009_A_095*'], cmr_keywords=('options[readable_granule_name][pattern]', 'true'), opts=search_opts)
+
+for product in gslc_results:
+    print(product.properties['fileID'])
+
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asf_search/basics.key b/asf_search/basics.key new file mode 100644 index 0000000..31ba559 --- /dev/null +++ b/asf_search/basics.key @@ -0,0 +1 @@ +{{ ASF_SB_1 }} \ No newline at end of file diff --git a/asf_search/basics/index.html b/asf_search/basics/index.html new file mode 100644 index 0000000..aa29b79 --- /dev/null +++ b/asf_search/basics/index.html @@ -0,0 +1,1507 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Basics - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

asf_search Basics#

+

Overview#

+

asf_search is a Python package for performing searches of the ASF catalog. In addition, it offers baseline functionality and download support. It is available through PyPi and Conda.

+
import asf_search as asf
+
+results = asf.granule_search(['ALPSRS279162400', 'ALPSRS279162200'])
+print(results)
+
+wkt = 'POLYGON((-135.7 58.2,-136.6 58.1,-135.8 56.9,-134.6 56.1,-134.9 58.0,-135.7 58.2))'
+results = asf.geo_search(platform=[asf.PLATFORM.SENTINEL1], intersectsWith=wkt, maxResults=10)
+print(results)
+
+

For an introductory walkthrough of asf_search, see the Jupyter Notebooks.

+

Installation#

+

In order to easily manage dependencies, we recommend using dedicated project environments via Anaconda/Miniconda or Python virtual environments.

+

asf_search can be installed into a conda environment with

+
conda install -c conda-forge asf_search
+
+

or into a virtual environment with

+
python -m pip install asf_search
+
+

Usage#

+

Programmatically searching for ASF data is made simple with asf_search. Several search functions are provided. Each search function returns an ASFSearchResults object:

+
    +
  • geo_search() Find product info over an area of interest using a WKT string
  • +
  • granule_search() Find product info using a list of scene names
  • +
  • product_search() Find product info using a list of product IDs
  • +
  • stack_from_id() Find a baseline stack of products using a reference scene
  • +
  • If the above search approaches do not meet your search needs, search() supports all available keywords:
      +
    • search() Find product info using any combination of search parameters
    • +
    +
  • +
  • Additionally, numerous constants are provided to ease the search process. Currently, we provide constants for beam mode, flight direction, instrument, platform, polarization, and product type. You can see the full list of constants here.
  • +
+

Additionally, asf_search supports downloading data, both from search results as provided by the above search functions, and directly on product URLs. An authenticated session is generally required. More information on available authentication methods can be found here. You may also authenticate using an ASFSession object and one of the following authentication methods. ASFSession is a subclass of Session.

+
    +
  • auth_with_creds('user', 'pass)
  • +
  • auth_with_token('EDL token')
  • +
  • auth_with_cookiejar(http.cookiejar)
  • +
+

If not using .netrc credentials, that session should be passed to whichever download method is being called, can be re-used, and is thread safe.

+

Example using .netrc:

+
results = ....
+results.download(path='....')
+
+

Example with manual authentication:

+
results = asf_search.granule_search([...])
+session = asf_search.ASFSession().auth_with_creds('user', 'pass')
+results.download(path='/Users/SARGuru/data', session=session)
+
+

Alternately, asf_search supports downloading an arbitrary list of URLs. All of the available authentication methods are supported:

+
urls = [...]
+asf_search.download_urls(urls=urls, path='/Users/SARGuru/data', session=ASFSession().auth_with_token('EDL token'))
+
+

Also note that ASFSearchResults.download() and the generic download_urls() function both accept a processes parameter which allows for parallel downloads.

+

Further examples of all of the above can be found in this sample script.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asf_search/downloading.key b/asf_search/downloading.key new file mode 100644 index 0000000..819c7d2 --- /dev/null +++ b/asf_search/downloading.key @@ -0,0 +1 @@ +{{ DOWNLOADING_1 }} \ No newline at end of file diff --git a/asf_search/downloading/index.html b/asf_search/downloading/index.html new file mode 100644 index 0000000..e86a62e --- /dev/null +++ b/asf_search/downloading/index.html @@ -0,0 +1,1570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Downloading - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Downloading#

+

Session Authentication#

+

asf_search supports downloading data, both from search results as provided by the search functions, and directly on product URLs. An authenticated session is generally required. asf_search uses Requests. Using .netrc credentials is the preferred method for authentication. More information on .netrc authentication can be found here.

+

Example using .netrc:

+
results = ....
+results.download(path='....')
+
+

If not using .netrc credentials, you may authenticate using an ASFSession object and one of the following authentication methods. ASFSession is a subclass of Session. The session should be passed to whichever download method is being called, can be re-used, and is thread safe.

+
    +
  • auth_with_creds('user', 'pass)
  • +
  • auth_with_token('EDL token')
  • +
  • auth_with_cookiejar(http.cookiejar)
  • +
+

Example with manual authentication:

+
results = asf_search.granule_search([...])
+session = asf_search.ASFSession().auth_with_creds('user', 'pass')
+results.download(path='/Users/SARGuru/data', session=session)
+
+

asf_search also supports downloading an arbitrary list of URLs. All of the available authentication methods are supported:

+
urls = [...]
+asf_search.download_urls(urls=urls, path='/Users/SARGuru/data', session=ASFSession().auth_with_token('EDL token'))
+
+

Also note that ASFSearchResults.download() and the generic download_urls() function both accept a processes parameter which allows for parallel downloads.

+

Methods#

+

download_urls()#

+

Downloads all products from the specified URLs to the specified location.

+

args

+
    +
  • urls: List of URLs from which to download
  • +
  • path: Local path in which to save the product
  • +
  • session: The session to use, in most cases should be authenticated beforehand
  • +
  • processes: Number of download processes to use. Defaults to 1 (i.e. sequential download)
  • +
+

download_url()#

+

Downloads a product from the specified URL to the specified location and (optional) filename.

+

args

+
    +
  • url: URL from which to download
  • +
  • path: Local path in which to save the product
  • +
  • filename: Optional filename to be used, extracted from the URL by default
  • +
  • session: The session to use, in most cases should be authenticated beforehand
  • +
+

remotezip()#

+

Configures and returns an authenticated remotezip.RemoteZip object, allowing downloading of +specific files from a given zip archive without downloading the entire archive.

+

args

+
    +
  • url: URL from which to download a zip archive
  • +
  • session: Authenticated ASFSession that RemoteZip will use to download from the zip product
  • +
+

returns:

+
    +
  • remotezip.RemoteZip object authenticated with the passed ASFSession object
  • +
+

Export Formats#

+

asf_search provides multiple export formats, in addition to the default asf_search format. Available formats are: geojson, csv, metalink, kml, jsonlite, jsonlite2.

+

Examples:

+
results = ....
+with open("search_results.csv", "w") as f:
+    f.writelines(results.csv())
+
+results = ....
+with open("search_results_jsonlite.json", "w") as f:
+    f.writelines(results.jsonlite())
+
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asf_search/exceptions.key b/asf_search/exceptions.key new file mode 100644 index 0000000..a1234bd --- /dev/null +++ b/asf_search/exceptions.key @@ -0,0 +1 @@ +{{ EXCEPTIONS_1 }} \ No newline at end of file diff --git a/asf_search/exceptions/index.html b/asf_search/exceptions/index.html new file mode 100644 index 0000000..6d1e781 --- /dev/null +++ b/asf_search/exceptions/index.html @@ -0,0 +1,1404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Exceptions - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Exceptions#

+

ASFError(Exception):

+
    +
  • Base ASF Exception, not intended for direct use
  • +
+

ASFSearchError(ASFError):

+
    +
  • Base search-related Exception
  • +
+

ASFSearch4xxError(ASFSearchError):

+
    +
  • Raise when SearchAPI returns a 4xx error
  • +
+

ASFSearch5xxError(ASFSearchError):

+
    +
  • Raise when SearchAPI returns a 5xx error
  • +
+

ASFServerError(ASFSearchError):

+
    +
  • Raise when SearchAPI returns an unknown error
  • +
+

ASFBaselineError(ASFSearchError):

+
    +
  • Raise when baseline related errors occur
  • +
+

ASFDownloadError(ASFError):

+
    +
  • Base download-related Exception
  • +
+

ASFAuthenticationError(ASFError):

+
    +
  • Base download-related Exception
  • +
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asf_search/searching.key b/asf_search/searching.key new file mode 100644 index 0000000..eb9b95b --- /dev/null +++ b/asf_search/searching.key @@ -0,0 +1 @@ +{{ SEARCHING_1 }} \ No newline at end of file diff --git a/asf_search/searching/index.html b/asf_search/searching/index.html new file mode 100644 index 0000000..526fe62 --- /dev/null +++ b/asf_search/searching/index.html @@ -0,0 +1,1995 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Searching - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Searching#

+

Each search function returns an ASFSearchResults object:

+
    +
  • geo_search() Find product info over an area of interest using a WKT string
  • +
  • granule_search() Find product info using a list of scene names
  • +
  • product_search() Find product info using a list of product IDs
  • +
  • stack_from_id() Find a baseline stack of products using a reference scene ID
  • +
  • If the above search approaches do not meet your search needs, search() supports all available keywords:
      +
    • search() Find product info using any combination combination of search parameters. See the keywords list below.
    • +
    +
  • +
+

Examples of some search workflows can be found in this sample script. You may also reference the Jupyter notebooks for example workflows.

+

For more advanced usage, see sections ASFSearchResults class and ASFProduct class.

+

Keywords#

+

Keywords are used to find the desired data. Use as many or as few keywords as needed. Available keywords and descriptions are listed below. Additionally, numerous constants are provided to ease the search process. Currently, we provide constants for beam mode, flight direction, instrument, platform, polarization, and product type. You can see the full list of constants here.

+

Dataset Parameters#

+
    +
  • +

    dataset

    +
      +
    • This is the preferred alternative keyword for 'platform' searches.
    • +
    • See the list of constants
    • +
    • Remote sensing platform that acquired the data. You may specify a single value, or a list of values.
    • +
    • You may also get the available list of constants by using help(asf_search.constants.DATASET)
    • +
    • Example:
        +
      • dataset=asf.DATASET.OPERA_S1
      • +
      +
    • +
    +
  • +
  • +

    platform

    +
      +
    • See the list of constants
    • +
    • Remote sensing platform that acquired the data. Sentinel-1 and ERS have multiple remote sensing platforms, and you may choose whether to specify a specific platform. You may specify a single value, or a list of values.
    • +
    • You may also get the available list of constants by using help(asf_search.constants.PLATFORM)
    • +
    • Example:
        +
      • platform=asf.PLATFORM.SENTINEL1A
      • +
      +
    • +
    +
  • +
  • +

    instrument

    +
      +
    • See the list of constants
    • +
    • Remote sensing instrument that acquired the data. For some platforms, such as ALOS, there are multiple instruments to choose from.
    • +
    • You may also get the available list of constants by using help(asf_search.constants.INSTRUMENT)
    • +
    • Example:
        +
      • instrument=asf.INSTRUMENT.AVNIR_2
      • +
      +
    • +
    +
  • +
  • +

    absoluteBurstID

    +
      +
    • Used for Sentinel-1 burst products. Each value identifies the stack of a burst cycle, representing all products generated over a specific sub-swath. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • single value: absoluteBurstID='102563902'
      • +
      • list of values: absoluteBurstID=['102563902', '103558145']
      • +
      +
    • +
    +
  • +
  • +

    absoluteOrbit

    +
      +
    • For ALOS, ERS-1, ERS-2, JERS-1, RADARSAT-1, Sentinel-1A, and Sentinel-1B this value corresponds to the orbit count within the orbit cycle. For UAVSAR it is the Flight ID. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • single value: absoluteOrbit=25436
      • +
      • range of values: absoluteOrbit=(12005, 12008)
      • +
      • list of values: absoluteOrbit=[25436, 25450]
      • +
      +
    • +
    +
  • +
  • +

    asfFrame

    +
      +
    • See also 'frame'
    • +
    • This is primarily an ASF / JAXA frame reference. However, some platforms use other conventions. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • single value: asfFrame=300
      • +
      • range of values: asfFrame=(2845, 2855)
      • +
      • list of values: asfFrame=[2800, 2845]
      • +
      +
    • +
    • Values:
        +
      • ERS, JERS, RADARSAT: ASF frames 0 to 900
      • +
      • ALOS PALSAR: JAXA frames 0 to 7200
      • +
      • SEASAT: ESA-like frames 208 to 3458
      • +
      • Sentinel-1: In-house values 0 to 1184
      • +
      +
    • +
    +
  • +
  • +

    beamMode

    +
      +
    • See the list of constants
    • +
    • The beam mode used to acquire the data.
    • +
    • You may also get the available list of constants by using help(asf_search.constants.BEAMMODE)
    • +
    • Example:
        +
      • beamMode=asf.BEAMMODE.POL
      • +
      +
    • +
    +
  • +
  • +

    beamSwath

    +
      +
    • The beam swath encompasses a look angle and beam mode. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • single value: beamSwath='IW'
      • +
      • list of values: beamSwath=['IW','EW']
      • +
      +
    • +
    +
  • +
  • +

    campaign

    +
      +
    • For UAVSAR, AIRSAR, and Sentinel-1 Interferogram datasets only. Search by the campaign name. You may specify a single value.
    • +
    • For a list of available campaigns, use the asf_search.campaigns() function. You must provide the desired platform.
        +
      • asf_search.campaigns(asf_search.PLATFORM.UAVSAR)
      • +
      +
    • +
    • Example:
        +
      • campaign='Purace Volcano, Colombia'
      • +
      +
    • +
    +
  • +
  • +

    maxDoppler

    +
      +
    • Doppler provides an indication of how much the look direction deviates from the ideal perpendicular flight direction acquisition.
    • +
    • Example:
        +
      • maxDoppler=1500 or maxDoppler=1500.5
      • +
      +
    • +
    +
  • +
  • +

    minDoppler

    +
      +
    • Doppler provides an indication of how much the look direction deviates from the ideal perpendicular flight direction acquisition.
    • +
    • Example:
        +
      • minDoppler=100 or minDoppler=1500.5
      • +
      +
    • +
    +
  • +
  • +

    maxFaradayRotation

    +
      +
    • Rotation of the polarization plane of the radar signal impacts imagery. HH and HV signals become mixed. One-way rotations exceeding 5° are likely to significantly reduce the accuracy of geophysical parameter recovery, such as forest biomass.
    • +
    • Example:
        +
      • maxFaradayRotation=3.5
      • +
      +
    • +
    +
  • +
  • +

    minFaradayRotation

    +
      +
    • Rotation of the polarization plane of the radar signal impacts imagery. HH and HV signals become mixed. One-way rotations exceeding 5° are likely to significantly reduce the accuracy of geophysical parameter recovery, such as forest biomass.
    • +
    • Example:
        +
      • minFaradayRotation=2
      • +
      +
    • +
    +
  • +
  • +

    flightDirection

    +
      +
    • See the list of constants
    • +
    • Satellite orbit direction during data acquisition. You may specify a single value.
    • +
    • You may also get the available list of constants by using help(asf_search.constants.FLIGHT_DIRECTION)
    • +
    • Example:
        +
      • flightDirection=asf.FLIGHT_DIRECTION.ASCENDING
      • +
      +
    • +
    +
  • +
  • +

    flightLine

    +
      +
    • Specify a flightline for UAVSAR or AIRSAR. You may specify a single value.
    • +
    • Example:
        +
      • UAVSAR: flightLine='05901'
      • +
      • AIRSAR: flightLine='gilmorecreek045-1.93044'
      • +
      +
    • +
    +
  • +
  • +

    frame

    +
      +
    • See also 'asfFrame'
    • +
    • ESA-referenced frames are offered to give users a universal framing convention. Each ESA frame has a corresponding ASF frame assigned. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • single value: frame=300
      • +
      • range of values: frame=(305, 315)
      • +
      • list of values: frame=[300, 303, 305]
      • +
      +
    • +
    • Values:
        +
      • Any number from 0 to 7200.
      • +
      +
    • +
    +
  • +
  • +

    fullBurstID

    +
      +
    • Used for Sentinel-1 burst products. Each value represents all burst products over a single sub-swath, corresponding to a near-perfect frame-aligned stack. This value is useful for baseline stacking. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • single value: fullBurstID='017_034465_IW2'
      • +
      • list of values: fullBurstID=['017_034465_IW2', '079_167884_IW1']
      • +
      +
    • +
    +
  • +
  • +

    groupID

    +
      +
    • List of specific group IDs. For some datasets, the group ID is the same as the scene name. For others, such as Sentinel-1, the group ID is unique for a group of scenes.
    • +
    • Example:
        +
      • groupID='S1A_IWDV_0112_0118_037147_150'
      • +
      +
    • +
    +
  • +
  • +

    lookDirection

    +
      +
    • Left or right direction of data acquisition. You may specify a single value.
    • +
    • Example:
        +
      • lookDirection='L'
      • +
      +
    • +
    • Values:
        +
      • R, RIGHT, L, LEFT
      • +
      +
    • +
    +
  • +
  • +

    offNadirAngle

    +
      +
    • Off-nadir angles for ALOS PALSAR. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • single value: offNadirAngle=21.5
      • +
      • range of values: offNadirAngle=(9.7, 14)
      • +
      • list of values: offNadirAngle=[21.5, 23.1]
      • +
      +
    • +
    • Values:
        +
      • Most common: 21.5, 23.1, 27.1, 34.3
      • +
      • Other: 9.7, 9.9, 13.8, 14, 16.2, 17.3, 17.9, 18, 19.2, 20.5, 21.5, 23.1, 24.2, 24.6, 25.2, 25.8, 25.9, 26.2, 27.1, 28.8, 30.8, 34.3, 36.9, 38.8, 41.5, 43.4, 45.2, 46.6, 47.8, 49, 50, 50.8
      • +
      +
    • +
    +
  • +
  • +

    operaBurstID

    +
      +
    • Used for Opera-S1 products. Each value identifies the specific burst for the product. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • single value: operaBurstID='T078-165486-IW2'
      • +
      • list of values: operaBurstID=['T078_165486_IW2', 'T078_165485_IW2']
      • +
      +
    • +
    +
  • +
  • +

    polarization

    +
      +
    • See the list of constants
    • +
    • A property of SAR electromagnetic waves that can be used to extract meaningful information about surface properties of the earth. You may specify a single value, or a list of values.
    • +
    • You may also get the available list of constants by using help(asf_search.constants.POLARIZATION)
    • +
    • Example:
        +
      • polarization=asf.POLARIZATION.VV
      • +
      +
    • +
    +
  • +
  • +

    processingLevel

    +
      +
    • See the list of constants
    • +
    • Level to which the data has been processed, also type of product.
    • +
    • You may also get the available list of constants by using help(asf_search.constants.PRODUCT_TYPE)
    • +
    • Example:
        +
      • processingLevel=asf.PRODUCT_TYPE.SLC
      • +
      +
    • +
    +
  • +
  • +

    relativeBurstID

    +
      +
    • Used for Sentinel-1 burst products. Each value identifies a burst cycle, and within each sub-swath these values are unique. You may specify a single value, or a list of values.
    • +
    • Example:
        +
      • single value: relativeBurstID='367299'
      • +
      • list of values: relativeBurstID=['167877', '167882']
      • +
      +
    • +
    +
  • +
  • +

    relativeOrbit

    +
      +
    • Path or track of satellite during data acquisition. For UAVSAR it is the Line ID. You may specify a single value, range of values, or a list of values.
    • +
    • Example:
        +
      • single value: relativeOrbit=5905
      • +
      • range of values: relativeOrbit=(2400, 2410)
      • +
      • list of values: relativeOrbit=[500, 580]
      • +
      +
    • +
    • Values:
        +
      • ALOS: 1-671
      • +
      • ERS-1: 0-2410
      • +
      • ERS-2: 0-500
      • +
      • JERS-1: 0-658
      • +
      • RADARSAT-1: 0-342
      • +
      • SEASAT: 1-243
      • +
      • UAVSAR: various
      • +
      +
    • +
    +
  • +
+

Geospatial Parameters#

+
    +
  • intersectsWith
      +
    • Search by polygon, a line segment (“linestring”), or a point defined in 2-D Well-Known Text (WKT). Each polygon must be explicitly closed, i.e. the first vertex and the last vertex of each listed polygon must be identical. Coordinate pairs for each vertex are in decimal degrees: longitude is followed by latitude.
    • +
    • Example:
        +
      • intersectsWith='POLYGON((-152.81 58.49,-154.90 57.49,-155.08 56.30,-153.82 56.34,-151.99 57.30,-151.43 58.19,-152.81 58.49))'
      • +
      • intersectsWith='LINESTRING(-119.543 37.925, -118.443 37.7421)'
      • +
      • intersectsWith='POINT(-119.543 37.925)'
      • +
      +
    • +
    +
  • +
+

Shape Validation#

+

If the AOI specified is its own Minimum Bounding Rectangle (MBR) in a mercator projection, the search results returned will instersect with the AOI in a mercator projection, regardless of width. This remains the case even if the international dateline is crossed within the AOI.

+

In order for an AOI to be considered its own MBR, it must meet the following criteria:

+
    +
  • Each vertex shares a latitude or longitude with its neighbors
  • +
  • East/West points share longitude
  • +
  • North/South points share latitude
  • +
+

AOIs that do not fit this criteria will have their points connected along great circles.

+

In addition, all AOIs are validated, and then simplified as needed. The process for this is:

+
    +
  1. Validate the input AOI. If it is not valid, an error is displayed.
  2. +
  3. Merge overlapping shapes.
  4. +
  5. Convex hull.
  6. +
  7. Any out-of-range index values are handled by clamping and wrapping them to the valid range of values.
  8. +
  9. Simplify points based on proximity threshold. The target is fewer than 400 points.
  10. +
+

Each of these steps is performed only when necessary to get the AOI to a single outline with fewer than 400 points. Any unnecessary steps are skipped.

+

Examples of validation and simplification:

+
    +
  • A self-intersecting polygon is provided:
      +
    • An error is displayed.
    • +
    +
  • +
  • A single outline is provided, consisting of 1000 points:
      +
    • A simplified version of the same outline is used, consisting of fewer than 400 points.
    • +
    +
  • +
  • Multiple geometries are provided, all of them overlapping at least in part:
      +
    • A single outline is returned, representing the outline of all the shapes combined.
    • +
    +
  • +
  • Multiple geometries are provided, at least some of them entirely non-overlapping:
      +
    • A single outline is returned, representing the convex hull of all the shapes together.
    • +
    +
  • +
+

Temporal Parameters#

+
    +
  • +

    processingDate

    +
      +
    • Limit results to records that have been processed at ASF since a given date and/or time.
    • +
    • Example:
        +
      • processingDate='2017-01-01T00:00:00UTC'
      • +
      +
    • +
    +
  • +
  • +

    start

    +
      +
    • Date of data acquisition. Can be used in combination with 'end'. You may enter natural language dates, or a date and/or time stamp. All times are in UTC.
    • +
    • Example:
        +
      • start='May 30, 2019'
      • +
      • start='yesterday'
      • +
      • start='2010-10-30T11:59:59Z'
      • +
      • start='1 week ago', end='now'
      • +
      +
    • +
    +
  • +
  • +

    end

    +
      +
    • Date of data acquisition. Can be used in combination with 'start'. You may enter natural language dates, or a date and/or time stamp. All times are in UTC.
        +
      • end='May 30, 2018'
      • +
      • end='today'
      • +
      • end='2021-04-30T11:59:59Z'
      • +
      • start='1 week ago', end='now'
      • +
      +
    • +
    +
  • +
  • +

    season

    +
      +
    • Start and end day of year for desired seasonal range. This keyword may be used in conjunction with start/end to specify a seasonal range within an overall date range. Values are based on the Julian calendar. You must specify both a season start and end date.
    • +
    • Example:
        +
      • season=[1, 31]
      • +
      • season=[45, 67]
      • +
      • season=[360, 10]
      • +
      +
    • +
    • Values:
        +
      • 1 through 365
      • +
      +
    • +
    +
  • +
+

Baseline Parameters#

+
    +
  • stack_from_id
      +
    • Input the scene name for which you wish to see baseline results.
    • +
    • stack_from_id may not be used in conjuction with other keywords.
    • +
    • Example:
        +
      • stack_from_id('S1A_IW_SLC__1SDV_20220215T225119_20220215T225146_041930_04FE2E_9252-SLC')
      • +
      +
    • +
    • See the Jupyter notebook for usage examples, as well as best practices.
    • +
    +
  • +
+

Results Parameters#

+
    +
  • maxResults
      +
    • Maximum number of data records to return.
    • +
    • Example:
        +
      • maxResults=10
      • +
      +
    • +
    +
  • +
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/ASFLogo-Blue2.png b/assets/images/ASFLogo-Blue2.png new file mode 100644 index 0000000..15a34c6 Binary files /dev/null and b/assets/images/ASFLogo-Blue2.png differ diff --git a/assets/images/asf-logo-blue-nav.png b/assets/images/asf-logo-blue-nav.png new file mode 100644 index 0000000..a3c1554 Binary files /dev/null and b/assets/images/asf-logo-blue-nav.png differ diff --git a/assets/images/favicon.ico b/assets/images/favicon.ico new file mode 100644 index 0000000..faae8c8 Binary files /dev/null and b/assets/images/favicon.ico differ diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000..1cf13b9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/images/map.png b/assets/images/map.png new file mode 100644 index 0000000..5072254 Binary files /dev/null and b/assets/images/map.png differ diff --git a/assets/javascripts/bundle.dff1b7c8.min.js b/assets/javascripts/bundle.dff1b7c8.min.js new file mode 100644 index 0000000..a89e799 --- /dev/null +++ b/assets/javascripts/bundle.dff1b7c8.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var gi=Object.create;var dr=Object.defineProperty;var xi=Object.getOwnPropertyDescriptor;var yi=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Ei=Object.getPrototypeOf,hr=Object.prototype.hasOwnProperty,Xr=Object.prototype.propertyIsEnumerable;var Jr=(e,t,r)=>t in e?dr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,I=(e,t)=>{for(var r in t||(t={}))hr.call(t,r)&&Jr(e,r,t[r]);if(Ht)for(var r of Ht(t))Xr.call(t,r)&&Jr(e,r,t[r]);return e};var Zr=(e,t)=>{var r={};for(var o in e)hr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Ht)for(var o of Ht(e))t.indexOf(o)<0&&Xr.call(e,o)&&(r[o]=e[o]);return r};var br=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var wi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of yi(t))!hr.call(e,n)&&n!==r&&dr(e,n,{get:()=>t[n],enumerable:!(o=xi(t,n))||o.enumerable});return e};var $t=(e,t,r)=>(r=e!=null?gi(Ei(e)):{},wi(t||!e||!e.__esModule?dr(r,"default",{value:e,enumerable:!0}):r,e));var to=br((vr,eo)=>{(function(e,t){typeof vr=="object"&&typeof eo!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(vr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(A){return!!(A&&A!==document&&A.nodeName!=="HTML"&&A.nodeName!=="BODY"&&"classList"in A&&"contains"in A.classList)}function c(A){var it=A.type,Ne=A.tagName;return!!(Ne==="INPUT"&&s[it]&&!A.readOnly||Ne==="TEXTAREA"&&!A.readOnly||A.isContentEditable)}function p(A){A.classList.contains("focus-visible")||(A.classList.add("focus-visible"),A.setAttribute("data-focus-visible-added",""))}function m(A){A.hasAttribute("data-focus-visible-added")&&(A.classList.remove("focus-visible"),A.removeAttribute("data-focus-visible-added"))}function f(A){A.metaKey||A.altKey||A.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(A){o=!1}function d(A){a(A.target)&&(o||c(A.target))&&p(A.target)}function b(A){a(A.target)&&(A.target.classList.contains("focus-visible")||A.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),m(A.target))}function _(A){document.visibilityState==="hidden"&&(n&&(o=!0),re())}function re(){document.addEventListener("mousemove",Y),document.addEventListener("mousedown",Y),document.addEventListener("mouseup",Y),document.addEventListener("pointermove",Y),document.addEventListener("pointerdown",Y),document.addEventListener("pointerup",Y),document.addEventListener("touchmove",Y),document.addEventListener("touchstart",Y),document.addEventListener("touchend",Y)}function Z(){document.removeEventListener("mousemove",Y),document.removeEventListener("mousedown",Y),document.removeEventListener("mouseup",Y),document.removeEventListener("pointermove",Y),document.removeEventListener("pointerdown",Y),document.removeEventListener("pointerup",Y),document.removeEventListener("touchmove",Y),document.removeEventListener("touchstart",Y),document.removeEventListener("touchend",Y)}function Y(A){A.target.nodeName&&A.target.nodeName.toLowerCase()==="html"||(o=!1,Z())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",_,!0),re(),r.addEventListener("focus",d,!0),r.addEventListener("blur",b,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var Vr=br((Mt,Dr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof Dr=="object"?Dr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return vi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),m=i(817),f=i.n(m);function u(F){try{return document.execCommand(F)}catch(S){return!1}}var d=function(S){var y=f()(S);return u("cut"),y},b=d;function _(F){var S=document.documentElement.getAttribute("dir")==="rtl",y=document.createElement("textarea");y.style.fontSize="12pt",y.style.border="0",y.style.padding="0",y.style.margin="0",y.style.position="absolute",y.style[S?"right":"left"]="-9999px";var R=window.pageYOffset||document.documentElement.scrollTop;return y.style.top="".concat(R,"px"),y.setAttribute("readonly",""),y.value=F,y}var re=function(S,y){var R=_(S);y.container.appendChild(R);var P=f()(R);return u("copy"),R.remove(),P},Z=function(S){var y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},R="";return typeof S=="string"?R=re(S,y):S instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(S==null?void 0:S.type)?R=re(S.value,y):(R=f()(S),u("copy")),R},Y=Z;function A(F){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?A=function(y){return typeof y}:A=function(y){return y&&typeof Symbol=="function"&&y.constructor===Symbol&&y!==Symbol.prototype?"symbol":typeof y},A(F)}var it=function(){var S=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},y=S.action,R=y===void 0?"copy":y,P=S.container,q=S.target,Me=S.text;if(R!=="copy"&&R!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&A(q)==="object"&&q.nodeType===1){if(R==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(R==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return Y(Me,{container:P});if(q)return R==="cut"?b(q):Y(q,{container:P})},Ne=it;function Ie(F){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Ie=function(y){return typeof y}:Ie=function(y){return y&&typeof Symbol=="function"&&y.constructor===Symbol&&y!==Symbol.prototype?"symbol":typeof y},Ie(F)}function pi(F,S){if(!(F instanceof S))throw new TypeError("Cannot call a class as a function")}function Gr(F,S){for(var y=0;y0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof P.action=="function"?P.action:this.defaultAction,this.target=typeof P.target=="function"?P.target:this.defaultTarget,this.text=typeof P.text=="function"?P.text:this.defaultText,this.container=Ie(P.container)==="object"?P.container:document.body}},{key:"listenClick",value:function(P){var q=this;this.listener=p()(P,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(P){var q=P.delegateTarget||P.currentTarget,Me=this.action(q)||"copy",kt=Ne({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(P){return ur("action",P)}},{key:"defaultTarget",value:function(P){var q=ur("target",P);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(P){return ur("text",P)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(P){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return Y(P,q)}},{key:"cut",value:function(P){return b(P)}},{key:"isSupported",value:function(){var P=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof P=="string"?[P]:P,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),y}(a()),vi=bi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(m,f,u,d,b){var _=p.apply(this,arguments);return m.addEventListener(u,_,b),{destroy:function(){m.removeEventListener(u,_,b)}}}function c(m,f,u,d,b){return typeof m.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof m=="string"&&(m=document.querySelectorAll(m)),Array.prototype.map.call(m,function(_){return a(_,f,u,d,b)}))}function p(m,f,u,d){return function(b){b.delegateTarget=s(b.target,f),b.delegateTarget&&d.call(m,b)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,b){if(!u&&!d&&!b)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(b))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,b);if(s.nodeList(u))return m(u,d,b);if(s.string(u))return f(u,d,b);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,b){return u.addEventListener(d,b),{destroy:function(){u.removeEventListener(d,b)}}}function m(u,d,b){return Array.prototype.forEach.call(u,function(_){_.addEventListener(d,b)}),{destroy:function(){Array.prototype.forEach.call(u,function(_){_.removeEventListener(d,b)})}}}function f(u,d,b){return a(document.body,u,d,b)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var _a=/["'&<>]/;Pn.exports=Aa;function Aa(e){var t=""+e,r=_a.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function U(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(b){f(i[0][3],b)}}function c(u){u.value instanceof Ze?Promise.resolve(u.value.v).then(p,m):f(i[0][2],u)}function p(u){a("next",u)}function m(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function no(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function De(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Pe=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(_){t={error:_}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var m=this.initialTeardown;if(C(m))try{m()}catch(_){i=_ instanceof It?_.errors:[_]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=Ee(f),d=u.next();!d.done;d=u.next()){var b=d.value;try{io(b)}catch(_){i=i!=null?i:[],_ instanceof It?i=D(D([],U(i)),U(_.errors)):i.push(_)}}}catch(_){o={error:_}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)io(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&De(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&De(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var xr=Pe.EMPTY;function Pt(e){return e instanceof Pe||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function io(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?xr:(this.currentObservers=null,a.push(r),new Pe(function(){o.currentObservers=null,De(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new j;return r.source=this,r},t.create=function(r,o){return new uo(r,o)},t}(j);var uo=function(e){ie(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:xr},t}(x);var yt={now:function(){return(yt.delegate||Date).now()},delegate:void 0};var Et=function(e){ie(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=yt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=mt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(mt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(Wt);var vo=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(Ut);var Te=new vo(bo);var T=new j(function(e){return e.complete()});function Nt(e){return e&&C(e.schedule)}function Mr(e){return e[e.length-1]}function Qe(e){return C(Mr(e))?e.pop():void 0}function Oe(e){return Nt(Mr(e))?e.pop():void 0}function Dt(e,t){return typeof Mr(e)=="number"?e.pop():t}var lt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Vt(e){return C(e==null?void 0:e.then)}function zt(e){return C(e[pt])}function qt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Kt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ki(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qt=ki();function Yt(e){return C(e==null?void 0:e[Qt])}function Bt(e){return oo(this,arguments,function(){var r,o,n,i;return Rt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,Ze(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,Ze(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,Ze(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Gt(e){return C(e==null?void 0:e.getReader)}function W(e){if(e instanceof j)return e;if(e!=null){if(zt(e))return Hi(e);if(lt(e))return $i(e);if(Vt(e))return Ri(e);if(qt(e))return go(e);if(Yt(e))return Ii(e);if(Gt(e))return Pi(e)}throw Kt(e)}function Hi(e){return new j(function(t){var r=e[pt]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function $i(e){return new j(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?L(function(n,i){return e(n,i,o)}):de,ge(1),r?He(t):Io(function(){return new Xt}))}}function Po(){for(var e=[],t=0;t=2,!0))}function le(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var m,f,u,d=0,b=!1,_=!1,re=function(){f==null||f.unsubscribe(),f=void 0},Z=function(){re(),m=u=void 0,b=_=!1},Y=function(){var A=m;Z(),A==null||A.unsubscribe()};return g(function(A,it){d++,!_&&!b&&re();var Ne=u=u!=null?u:r();it.add(function(){d--,d===0&&!_&&!b&&(f=kr(Y,c))}),Ne.subscribe(it),!m&&d>0&&(m=new tt({next:function(Ie){return Ne.next(Ie)},error:function(Ie){_=!0,re(),f=kr(Z,n,Ie),Ne.error(Ie)},complete:function(){b=!0,re(),f=kr(Z,s),Ne.complete()}}),W(A).subscribe(m))})(p)}}function kr(e,t){for(var r=[],o=2;oe.next(document)),e}function z(e,t=document){return Array.from(t.querySelectorAll(e))}function N(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function Re(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}var ea=M(h(document.body,"focusin"),h(document.body,"focusout")).pipe(ke(1),V(void 0),l(()=>Re()||document.body),B(1));function er(e){return ea.pipe(l(t=>e.contains(t)),G())}function Je(e){return{x:e.offsetLeft,y:e.offsetTop}}function Uo(e){return M(h(window,"load"),h(window,"resize")).pipe(Ae(0,Te),l(()=>Je(e)),V(Je(e)))}function tr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return M(h(e,"scroll"),h(window,"resize")).pipe(Ae(0,Te),l(()=>tr(e)),V(tr(e)))}function No(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)No(e,r)}function O(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)No(o,n);return o}function rr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function ht(e){let t=O("script",{src:e});return $(()=>(document.head.appendChild(t),M(h(t,"load"),h(t,"error").pipe(v(()=>St(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),k(()=>document.head.removeChild(t)),ge(1))))}var Do=new x,ta=$(()=>typeof ResizeObserver=="undefined"?ht("https://unpkg.com/resize-observer-polyfill"):H(void 0)).pipe(l(()=>new ResizeObserver(e=>{for(let t of e)Do.next(t)})),v(e=>M(Ve,H(e)).pipe(k(()=>e.disconnect()))),B(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function xe(e){return ta.pipe(w(t=>t.observe(e)),v(t=>Do.pipe(L(({target:r})=>r===e),k(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function or(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var Vo=new x,ra=$(()=>H(new IntersectionObserver(e=>{for(let t of e)Vo.next(t)},{threshold:0}))).pipe(v(e=>M(Ve,H(e)).pipe(k(()=>e.disconnect()))),B(1));function nr(e){return ra.pipe(w(t=>t.observe(e)),v(t=>Vo.pipe(L(({target:r})=>r===e),k(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function zo(e,t=16){return dt(e).pipe(l(({y:r})=>{let o=he(e),n=bt(e);return r>=n.height-o.height-t}),G())}var ir={drawer:N("[data-md-toggle=drawer]"),search:N("[data-md-toggle=search]")};function qo(e){return ir[e].checked}function Ke(e,t){ir[e].checked!==t&&ir[e].click()}function We(e){let t=ir[e];return h(t,"change").pipe(l(()=>t.checked),V(t.checked))}function oa(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function na(){return M(h(window,"compositionstart").pipe(l(()=>!0)),h(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function Ko(){let e=h(window,"keydown").pipe(L(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:qo("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),L(({mode:t,type:r})=>{if(t==="global"){let o=Re();if(typeof o!="undefined")return!oa(o,r)}return!0}),le());return na().pipe(v(t=>t?T:e))}function fe(){return new URL(location.href)}function ot(e){location.href=e.href}function Qo(){return new x}function Yo(){return location.hash.slice(1)}function Pr(e){let t=O("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function ia(e){return M(h(window,"hashchange"),e).pipe(l(Yo),V(Yo()),L(t=>t.length>0),B(1))}function Bo(e){return ia(e).pipe(l(t=>ce(`[id="${t}"]`)),L(t=>typeof t!="undefined"))}function Fr(e){let t=matchMedia(e);return Zt(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function Go(){let e=matchMedia("print");return M(h(window,"beforeprint").pipe(l(()=>!0)),h(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function jr(e,t){return e.pipe(v(r=>r?t():T))}function ar(e,t={credentials:"same-origin"}){return me(fetch(`${e}`,t)).pipe(pe(()=>T),v(r=>r.status!==200?St(()=>new Error(r.statusText)):H(r)))}function Ue(e,t){return ar(e,t).pipe(v(r=>r.json()),B(1))}function Jo(e,t){let r=new DOMParser;return ar(e,t).pipe(v(o=>o.text()),l(o=>r.parseFromString(o,"text/xml")),B(1))}function Xo(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function Zo(){return M(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(l(Xo),V(Xo()))}function en(){return{width:innerWidth,height:innerHeight}}function tn(){return h(window,"resize",{passive:!0}).pipe(l(en),V(en()))}function rn(){return Q([Zo(),tn()]).pipe(l(([e,t])=>({offset:e,size:t})),B(1))}function sr(e,{viewport$:t,header$:r}){let o=t.pipe(X("size")),n=Q([o,r]).pipe(l(()=>Je(e)));return Q([r,t,n]).pipe(l(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function aa(e){return h(e,"message",t=>t.data)}function sa(e){let t=new x;return t.subscribe(r=>e.postMessage(r)),t}function on(e,t=new Worker(e)){let r=aa(t),o=sa(t),n=new x;n.subscribe(o);let i=o.pipe(J(),ee(!0));return n.pipe(J(),qe(r.pipe(K(i))),le())}var ca=N("#__config"),vt=JSON.parse(ca.textContent);vt.base=`${new URL(vt.base,fe())}`;function ue(){return vt}function te(e){return vt.features.includes(e)}function be(e,t){return typeof t!="undefined"?vt.translations[e].replace("#",t.toString()):vt.translations[e]}function ye(e,t=document){return N(`[data-md-component=${e}]`,t)}function ne(e,t=document){return z(`[data-md-component=${e}]`,t)}function pa(e){let t=N(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(l(()=>N(".md-typeset",e)),l(r=>({hash:__md_hash(r.innerHTML)})))}function nn(e){if(!te("announce.dismiss")||!e.childElementCount)return T;if(!e.hidden){let t=N(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return $(()=>{let t=new x;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),pa(e).pipe(w(r=>t.next(r)),k(()=>t.complete()),l(r=>I({ref:e},r)))})}function ma(e,{target$:t}){return t.pipe(l(r=>({hidden:r!==e})))}function an(e,t){let r=new x;return r.subscribe(({hidden:o})=>{e.hidden=o}),ma(e,t).pipe(w(o=>r.next(o)),k(()=>r.complete()),l(o=>I({ref:e},o)))}function la(e,t){let r=$(()=>Q([Uo(e),dt(t)])).pipe(l(([{x:o,y:n},i])=>{let{width:s,height:a}=he(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return er(e).pipe(v(o=>r.pipe(l(n=>({active:o,offset:n})),ge(+!o||1/0))))}function sn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return $(()=>{let i=new x,s=i.pipe(J(),ee(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),nr(e).pipe(K(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),M(i.pipe(L(({active:a})=>a)),i.pipe(ke(250),L(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Ae(16,Te)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(Rr(125,Te),L(()=>!!e.offsetParent),l(()=>e.offsetParent.getBoundingClientRect()),l(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(K(s),L(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(K(s),oe(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let m=e.parentElement.closest(".md-annotation");m instanceof HTMLElement?m.focus():(p=Re())==null||p.blur()}}),r.pipe(K(s),L(a=>a===o),ze(125)).subscribe(()=>e.focus()),la(e,t).pipe(w(a=>i.next(a)),k(()=>i.complete()),l(a=>I({ref:e},a)))})}function Wr(e){return O("div",{class:"md-tooltip",id:e},O("div",{class:"md-tooltip__inner md-typeset"}))}function cn(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return O("aside",{class:"md-annotation",tabIndex:0},Wr(t),O("a",{href:r,class:"md-annotation__index",tabIndex:-1},O("span",{"data-md-annotation-id":e})))}else return O("aside",{class:"md-annotation",tabIndex:0},Wr(t),O("span",{class:"md-annotation__index",tabIndex:-1},O("span",{"data-md-annotation-id":e})))}function pn(e){return O("button",{class:"md-clipboard md-icon",title:be("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function Ur(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,O("del",null,p)," "],[]).slice(0,-1),i=ue(),s=new URL(e.location,i.base);te("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=ue();return O("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},O("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&O("div",{class:"md-search-result__icon md-icon"}),r>0&&O("h1",null,e.title),r<=0&&O("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return O("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&O("p",{class:"md-search-result__terms"},be("search.result.term.missing"),": ",...n)))}function mn(e){let t=e[0].score,r=[...e],o=ue(),n=r.findIndex(m=>!`${new URL(m.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(m=>m.scoreUr(m,1)),...c.length?[O("details",{class:"md-search-result__more"},O("summary",{tabIndex:-1},O("div",null,c.length>0&&c.length===1?be("search.result.more.one"):be("search.result.more.other",c.length))),...c.map(m=>Ur(m,1)))]:[]];return O("li",{class:"md-search-result__item"},p)}function ln(e){return O("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>O("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?rr(r):r)))}function Nr(e){let t=`tabbed-control tabbed-control--${e}`;return O("div",{class:t,hidden:!0},O("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function fn(e){return O("div",{class:"md-typeset__scrollwrap"},O("div",{class:"md-typeset__table"},e))}function fa(e){let t=ue(),r=new URL(`../${e.version}/`,t.base);return O("li",{class:"md-version__item"},O("a",{href:`${r}`,class:"md-version__link"},e.title))}function un(e,t){return O("div",{class:"md-version"},O("button",{class:"md-version__current","aria-label":be("select.version")},t.title),O("ul",{class:"md-version__list"},e.map(fa)))}function ua(e){return e.tagName==="CODE"?z(".c, .c1, .cm",e):[e]}function da(e){let t=[];for(let r of ua(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function dn(e,t){t.append(...Array.from(e.childNodes))}function cr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of da(t)){let[,c]=a.textContent.match(/\((\d+)\)/);ce(`:scope > li:nth-child(${c})`,e)&&(s.set(c,cn(c,i)),a.replaceWith(s.get(c)))}return s.size===0?T:$(()=>{let a=new x,c=a.pipe(J(),ee(!0)),p=[];for(let[m,f]of s)p.push([N(".md-typeset",f),N(`:scope > li:nth-child(${m})`,e)]);return o.pipe(K(c)).subscribe(m=>{e.hidden=!m,e.classList.toggle("md-annotation-list",m);for(let[f,u]of p)m?dn(f,u):dn(u,f)}),M(...[...s].map(([,m])=>sn(m,t,{target$:r}))).pipe(k(()=>a.complete()),le())})}function hn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return hn(t)}}function bn(e,t){return $(()=>{let r=hn(e);return typeof r!="undefined"?cr(r,e,t):T})}var gn=$t(Vr());var ha=0;function xn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return xn(t)}}function vn(e){return xe(e).pipe(l(({width:t})=>({scrollable:bt(e).width>t})),X("scrollable"))}function yn(e,t){let{matches:r}=matchMedia("(hover)"),o=$(()=>{let n=new x;if(n.subscribe(({scrollable:s})=>{s&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")}),gn.default.isSupported()&&(e.closest(".copy")||te("content.code.copy")&&!e.closest(".no-copy"))){let s=e.closest("pre");s.id=`__code_${ha++}`,s.insertBefore(pn(s.id),e)}let i=e.closest(".highlight");if(i instanceof HTMLElement){let s=xn(i);if(typeof s!="undefined"&&(i.classList.contains("annotate")||te("content.code.annotate"))){let a=cr(s,e,t);return vn(e).pipe(w(c=>n.next(c)),k(()=>n.complete()),l(c=>I({ref:e},c)),qe(xe(i).pipe(l(({width:c,height:p})=>c&&p),G(),v(c=>c?a:T))))}}return vn(e).pipe(w(s=>n.next(s)),k(()=>n.complete()),l(s=>I({ref:e},s)))});return te("content.lazy")?nr(e).pipe(L(n=>n),ge(1),v(()=>o)):o}function ba(e,{target$:t,print$:r}){let o=!0;return M(t.pipe(l(n=>n.closest("details:not([open])")),L(n=>e===n),l(()=>({action:"open",reveal:!0}))),r.pipe(L(n=>n||!o),w(()=>o=e.open),l(n=>({action:n?"open":"close"}))))}function En(e,t){return $(()=>{let r=new x;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),ba(e,t).pipe(w(o=>r.next(o)),k(()=>r.complete()),l(o=>I({ref:e},o)))})}var wn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var zr,ga=0;function xa(){return typeof mermaid=="undefined"||mermaid instanceof Element?ht("https://unpkg.com/mermaid@9.4.3/dist/mermaid.min.js"):H(void 0)}function Sn(e){return e.classList.remove("mermaid"),zr||(zr=xa().pipe(w(()=>mermaid.initialize({startOnLoad:!1,themeCSS:wn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),l(()=>{}),B(1))),zr.subscribe(()=>{e.classList.add("mermaid");let t=`__mermaid_${ga++}`,r=O("div",{class:"mermaid"}),o=e.textContent;mermaid.mermaidAPI.render(t,o,(n,i)=>{let s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})}),zr.pipe(l(()=>({ref:e})))}var Tn=O("table");function On(e){return e.replaceWith(Tn),Tn.replaceWith(fn(e)),H({ref:e})}function ya(e){let t=z(":scope > input",e),r=t.find(o=>o.checked)||t[0];return M(...t.map(o=>h(o,"change").pipe(l(()=>N(`label[for="${o.id}"]`))))).pipe(V(N(`label[for="${r.id}"]`)),l(o=>({active:o})))}function Mn(e,{viewport$:t}){let r=Nr("prev");e.append(r);let o=Nr("next");e.append(o);let n=N(".tabbed-labels",e);return $(()=>{let i=new x,s=i.pipe(J(),ee(!0));return Q([i,xe(e)]).pipe(Ae(1,Te),K(s)).subscribe({next([{active:a},c]){let p=Je(a),{width:m}=he(a);e.style.setProperty("--md-indicator-x",`${p.x}px`),e.style.setProperty("--md-indicator-width",`${m}px`);let f=tr(n);(p.xf.x+c.width)&&n.scrollTo({left:Math.max(0,p.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),Q([dt(n),xe(n)]).pipe(K(s)).subscribe(([a,c])=>{let p=bt(n);r.hidden=a.x<16,o.hidden=a.x>p.width-c.width-16}),M(h(r,"click").pipe(l(()=>-1)),h(o,"click").pipe(l(()=>1))).pipe(K(s)).subscribe(a=>{let{width:c}=he(n);n.scrollBy({left:c*a,behavior:"smooth"})}),te("content.tabs.link")&&i.pipe(je(1),oe(t)).subscribe(([{active:a},{offset:c}])=>{let p=a.innerText.trim();if(a.hasAttribute("data-md-switching"))a.removeAttribute("data-md-switching");else{let m=e.offsetTop-c.y;for(let u of z("[data-tabs]"))for(let d of z(":scope > input",u)){let b=N(`label[for="${d.id}"]`);if(b!==a&&b.innerText.trim()===p){b.setAttribute("data-md-switching",""),d.click();break}}window.scrollTo({top:e.offsetTop-m});let f=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([p,...f])])}}),i.pipe(K(s)).subscribe(()=>{for(let a of z("audio, video",e))a.pause()}),ya(e).pipe(w(a=>i.next(a)),k(()=>i.complete()),l(a=>I({ref:e},a)))}).pipe(rt(ae))}function Ln(e,{viewport$:t,target$:r,print$:o}){return M(...z(".annotate:not(.highlight)",e).map(n=>bn(n,{target$:r,print$:o})),...z("pre:not(.mermaid) > code",e).map(n=>yn(n,{target$:r,print$:o})),...z("pre.mermaid",e).map(n=>Sn(n)),...z("table:not([class])",e).map(n=>On(n)),...z("details",e).map(n=>En(n,{target$:r,print$:o})),...z("[data-tabs]",e).map(n=>Mn(n,{viewport$:t})))}function Ea(e,{alert$:t}){return t.pipe(v(r=>M(H(!0),H(!1).pipe(ze(2e3))).pipe(l(o=>({message:r,active:o})))))}function _n(e,t){let r=N(".md-typeset",e);return $(()=>{let o=new x;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ea(e,t).pipe(w(n=>o.next(n)),k(()=>o.complete()),l(n=>I({ref:e},n)))})}function wa({viewport$:e}){if(!te("header.autohide"))return H(!1);let t=e.pipe(l(({offset:{y:n}})=>n),Ce(2,1),l(([n,i])=>[nMath.abs(i-n.y)>100),l(([,[n]])=>n),G()),o=We("search");return Q([e,o]).pipe(l(([{offset:n},i])=>n.y>400&&!i),G(),v(n=>n?r:H(!1)),V(!1))}function An(e,t){return $(()=>Q([xe(e),wa(t)])).pipe(l(([{height:r},o])=>({height:r,hidden:o})),G((r,o)=>r.height===o.height&&r.hidden===o.hidden),B(1))}function Cn(e,{header$:t,main$:r}){return $(()=>{let o=new x,n=o.pipe(J(),ee(!0));return o.pipe(X("active"),Ge(t)).subscribe(([{active:i},{hidden:s}])=>{e.classList.toggle("md-header--shadow",i&&!s),e.hidden=s}),r.subscribe(o),t.pipe(K(n),l(i=>I({ref:e},i)))})}function Sa(e,{viewport$:t,header$:r}){return sr(e,{viewport$:t,header$:r}).pipe(l(({offset:{y:o}})=>{let{height:n}=he(e);return{active:o>=n}}),X("active"))}function kn(e,t){return $(()=>{let r=new x;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=ce(".md-content h1");return typeof o=="undefined"?T:Sa(o,t).pipe(w(n=>r.next(n)),k(()=>r.complete()),l(n=>I({ref:e},n)))})}function Hn(e,{viewport$:t,header$:r}){let o=r.pipe(l(({height:i})=>i),G()),n=o.pipe(v(()=>xe(e).pipe(l(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),X("bottom"))));return Q([o,n,t]).pipe(l(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),G((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function Ta(e){let t=__md_get("__palette")||{index:e.findIndex(r=>matchMedia(r.getAttribute("data-md-color-media")).matches)};return H(...e).pipe(se(r=>h(r,"change").pipe(l(()=>r))),V(e[Math.max(0,t.index)]),l(r=>({index:e.indexOf(r),color:{scheme:r.getAttribute("data-md-color-scheme"),primary:r.getAttribute("data-md-color-primary"),accent:r.getAttribute("data-md-color-accent")}})),B(1))}function $n(e){let t=O("meta",{name:"theme-color"});document.head.appendChild(t);let r=O("meta",{name:"color-scheme"});return document.head.appendChild(r),$(()=>{let o=new x;o.subscribe(i=>{document.body.setAttribute("data-md-color-switching","");for(let[s,a]of Object.entries(i.color))document.body.setAttribute(`data-md-color-${s}`,a);for(let s=0;s{let i=ye("header"),s=window.getComputedStyle(i);return r.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(a=>(+a).toString(16).padStart(2,"0")).join("")})).subscribe(i=>t.content=`#${i}`),o.pipe(_e(ae)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")});let n=z("input",e);return Ta(n).pipe(w(i=>o.next(i)),k(()=>o.complete()),l(i=>I({ref:e},i)))})}var qr=$t(Vr());function Oa(e){e.setAttribute("data-md-copying","");let t=e.innerText;return e.removeAttribute("data-md-copying"),t}function Rn({alert$:e}){qr.default.isSupported()&&new j(t=>{new qr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Oa(N(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(w(t=>{t.trigger.focus()}),l(()=>be("clipboard.copied"))).subscribe(e)}function Ma(e){if(e.length<2)return[""];let[t,r]=[...e].sort((n,i)=>n.length-i.length).map(n=>n.replace(/[^/]+$/,"")),o=0;if(t===r)o=t.length;else for(;t.charCodeAt(o)===r.charCodeAt(o);)o++;return e.map(n=>n.replace(t.slice(0,o),""))}function pr(e){let t=__md_get("__sitemap",sessionStorage,e);if(t)return H(t);{let r=ue();return Jo(new URL("sitemap.xml",e||r.base)).pipe(l(o=>Ma(z("loc",o).map(n=>n.textContent))),pe(()=>T),He([]),w(o=>__md_set("__sitemap",o,sessionStorage,e)))}}function In({location$:e,viewport$:t}){let r=ue();if(location.protocol==="file:")return T;let o=pr().pipe(l(p=>p.map(m=>`${new URL(m,r.base)}`))),n=h(document.body,"click").pipe(oe(o),v(([p,m])=>{if(!(p.target instanceof Element))return T;let f=p.target.closest("a");if(f===null)return T;if(f.target||p.metaKey||p.ctrlKey)return T;let u=new URL(f.href);return u.search=u.hash="",m.includes(`${u}`)?(p.preventDefault(),H(new URL(f.href))):T}),le());n.pipe(ge(1)).subscribe(()=>{let p=ce("link[rel=icon]");typeof p!="undefined"&&(p.href=p.href)}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),n.pipe(oe(t)).subscribe(([p,{offset:m}])=>{history.scrollRestoration="manual",history.replaceState(m,""),history.pushState(null,"",p)}),n.subscribe(e);let i=e.pipe(V(fe()),X("pathname"),je(1),v(p=>ar(p).pipe(pe(()=>(ot(p),T))))),s=new DOMParser,a=i.pipe(v(p=>p.text()),v(p=>{let m=s.parseFromString(p,"text/html");for(let u of["title","link[rel=canonical]","meta[name=author]","meta[name=description]","[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...te("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let d=ce(u),b=ce(u,m);typeof d!="undefined"&&typeof b!="undefined"&&d.replaceWith(b)}let f=ye("container");return Fe(z("script",f)).pipe(v(u=>{let d=m.createElement("script");if(u.src){for(let b of u.getAttributeNames())d.setAttribute(b,u.getAttribute(b));return u.replaceWith(d),new j(b=>{d.onload=()=>b.complete()})}else return d.textContent=u.textContent,u.replaceWith(d),T}),J(),ee(m))}),le());return h(window,"popstate").pipe(l(fe)).subscribe(e),e.pipe(V(fe()),Ce(2,1),v(([p,m])=>p.pathname===m.pathname&&p.hash!==m.hash?H(m):T)).subscribe(p=>{var m,f;history.state!==null||!p.hash?window.scrollTo(0,(f=(m=history.state)==null?void 0:m.y)!=null?f:0):(history.scrollRestoration="auto",Pr(p.hash),history.scrollRestoration="manual")}),a.pipe(oe(e)).subscribe(([,p])=>{var m,f;history.state!==null||!p.hash?window.scrollTo(0,(f=(m=history.state)==null?void 0:m.y)!=null?f:0):Pr(p.hash)}),a.pipe(v(()=>t),X("offset"),ke(100)).subscribe(({offset:p})=>{history.replaceState(p,"")}),a}var jn=$t(Fn());function Wn(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,jn.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function Lt(e){return e.type===1}function mr(e){return e.type===3}function Un(e,t){let r=on(e);return M(H(location.protocol!=="file:"),We("search")).pipe($e(o=>o),v(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:te("search.suggest")}}})),r}function Nn({document$:e}){let t=ue(),r=Ue(new URL("../versions.json",t.base)).pipe(pe(()=>T)),o=r.pipe(l(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(l(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),v(n=>h(document.body,"click").pipe(L(i=>!i.metaKey&&!i.ctrlKey),oe(o),v(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?T:(i.preventDefault(),H(c))}}return T}),v(i=>{let{version:s}=n.get(i);return pr(new URL(i)).pipe(l(a=>{let p=fe().href.replace(t.base,"");return a.includes(p.split("#")[0])?new URL(`../${s}/${p}`,t.base):new URL(i)}))})))).subscribe(n=>ot(n)),Q([r,o]).subscribe(([n,i])=>{N(".md-header__topic").appendChild(un(n,i))}),e.pipe(v(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases)if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of ne("outdated"))a.hidden=!1})}function ka(e,{worker$:t}){let{searchParams:r}=fe();r.has("q")&&(Ke("search",!0),e.value=r.get("q"),e.focus(),We("search").pipe($e(i=>!i)).subscribe(()=>{let i=new URL(location.href);i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=er(e),n=M(t.pipe($e(Lt)),h(e,"keyup"),o).pipe(l(()=>e.value),G());return Q([n,o]).pipe(l(([i,s])=>({value:i,focus:s})),B(1))}function Dn(e,{worker$:t}){let r=new x,o=r.pipe(J(),ee(!0));Q([t.pipe($e(Lt)),r],(i,s)=>s).pipe(X("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(X("focus")).subscribe(({focus:i})=>{i&&Ke("search",i)}),h(e.form,"reset").pipe(K(o)).subscribe(()=>e.focus());let n=N("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),ka(e,{worker$:t}).pipe(w(i=>r.next(i)),k(()=>r.complete()),l(i=>I({ref:e},i)),B(1))}function Vn(e,{worker$:t,query$:r}){let o=new x,n=zo(e.parentElement).pipe(L(Boolean)),i=e.parentElement,s=N(":scope > :first-child",e),a=N(":scope > :last-child",e);We("search").subscribe(m=>a.setAttribute("role",m?"list":"presentation")),o.pipe(oe(r),Hr(t.pipe($e(Lt)))).subscribe(([{items:m},{value:f}])=>{switch(m.length){case 0:s.textContent=f.length?be("search.result.none"):be("search.result.placeholder");break;case 1:s.textContent=be("search.result.one");break;default:let u=rr(m.length);s.textContent=be("search.result.other",u)}});let c=o.pipe(w(()=>a.innerHTML=""),v(({items:m})=>M(H(...m.slice(0,10)),H(...m.slice(10)).pipe(Ce(4),Ir(n),v(([f])=>f)))),l(mn),le());return c.subscribe(m=>a.appendChild(m)),c.pipe(se(m=>{let f=ce("details",m);return typeof f=="undefined"?T:h(f,"toggle").pipe(K(o),l(()=>f))})).subscribe(m=>{m.open===!1&&m.offsetTop<=i.scrollTop&&i.scrollTo({top:m.offsetTop})}),t.pipe(L(mr),l(({data:m})=>m)).pipe(w(m=>o.next(m)),k(()=>o.complete()),l(m=>I({ref:e},m)))}function Ha(e,{query$:t}){return t.pipe(l(({value:r})=>{let o=fe();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function zn(e,t){let r=new x,o=r.pipe(J(),ee(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(K(o)).subscribe(n=>n.preventDefault()),Ha(e,t).pipe(w(n=>r.next(n)),k(()=>r.complete()),l(n=>I({ref:e},n)))}function qn(e,{worker$:t,keyboard$:r}){let o=new x,n=ye("search-query"),i=M(h(n,"keydown"),h(n,"focus")).pipe(_e(ae),l(()=>n.value),G());return o.pipe(Ge(i),l(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let m=a[a.length-1];m.startsWith(p[p.length-1])&&(p[p.length-1]=m)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(L(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(L(mr),l(({data:a})=>a)).pipe(w(a=>o.next(a)),k(()=>o.complete()),l(()=>({ref:e})))}function Kn(e,{index$:t,keyboard$:r}){let o=ue();try{let n=Un(o.search,t),i=ye("search-query",e),s=ye("search-result",e);h(e,"click").pipe(L(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>Ke("search",!1)),r.pipe(L(({mode:c})=>c==="search")).subscribe(c=>{let p=Re();switch(c.type){case"Enter":if(p===i){let m=new Map;for(let f of z(":first-child [href]",s)){let u=f.firstElementChild;m.set(f,parseFloat(u.getAttribute("data-md-score")))}if(m.size){let[[f]]=[...m].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":Ke("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let m=[i,...z(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,m.indexOf(p))+m.length+(c.type==="ArrowUp"?-1:1))%m.length);m[f].focus()}c.claim();break;default:i!==Re()&&i.focus()}}),r.pipe(L(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=Dn(i,{worker$:n});return M(a,Vn(s,{worker$:n,query$:a})).pipe(qe(...ne("search-share",e).map(c=>zn(c,{query$:a})),...ne("search-suggest",e).map(c=>qn(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ve}}function Qn(e,{index$:t,location$:r}){return Q([t,r.pipe(V(fe()),L(o=>!!o.searchParams.get("h")))]).pipe(l(([o,n])=>Wn(o.config)(n.searchParams.get("h"))),l(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=O("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function $a(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return Q([r,t]).pipe(l(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),G((i,s)=>i.height===s.height&&i.locked===s.locked))}function Kr(e,o){var n=o,{header$:t}=n,r=Zr(n,["header$"]);let i=N(".md-sidebar__scrollwrap",e),{y:s}=Je(i);return $(()=>{let a=new x,c=a.pipe(J(),ee(!0)),p=a.pipe(Ae(0,Te));return p.pipe(oe(t)).subscribe({next([{height:m},{height:f}]){i.style.height=`${m-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe($e()).subscribe(()=>{for(let m of z(".md-nav__link--active[href]",e)){let f=or(m);if(typeof f!="undefined"){let u=m.offsetTop-f.offsetTop,{height:d}=he(f);f.scrollTo({top:u-d/2})}}}),me(z("label[tabindex]",e)).pipe(se(m=>h(m,"click").pipe(l(()=>m),K(c)))).subscribe(m=>{let f=N(`[id="${m.htmlFor}"]`);N(`[aria-labelledby="${m.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),$a(e,r).pipe(w(m=>a.next(m)),k(()=>a.complete()),l(m=>I({ref:e},m)))})}function Yn(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return Tt(Ue(`${r}/releases/latest`).pipe(pe(()=>T),l(o=>({version:o.tag_name})),He({})),Ue(r).pipe(pe(()=>T),l(o=>({stars:o.stargazers_count,forks:o.forks_count})),He({}))).pipe(l(([o,n])=>I(I({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return Ue(r).pipe(l(o=>({repositories:o.public_repos})),He({}))}}function Bn(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ue(r).pipe(pe(()=>T),l(({star_count:o,forks_count:n})=>({stars:o,forks:n})),He({}))}function Gn(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return Yn(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return Bn(r,o)}return T}var Ra;function Ia(e){return Ra||(Ra=$(()=>{let t=__md_get("__source",sessionStorage);if(t)return H(t);if(ne("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return T}return Gn(e.href).pipe(w(o=>__md_set("__source",o,sessionStorage)))}).pipe(pe(()=>T),L(t=>Object.keys(t).length>0),l(t=>({facts:t})),B(1)))}function Jn(e){let t=N(":scope > :last-child",e);return $(()=>{let r=new x;return r.subscribe(({facts:o})=>{t.appendChild(ln(o)),t.classList.add("md-source__repository--active")}),Ia(e).pipe(w(o=>r.next(o)),k(()=>r.complete()),l(o=>I({ref:e},o)))})}function Pa(e,{viewport$:t,header$:r}){return xe(document.body).pipe(v(()=>sr(e,{header$:r,viewport$:t})),l(({offset:{y:o}})=>({hidden:o>=10})),X("hidden"))}function Xn(e,t){return $(()=>{let r=new x;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(te("navigation.tabs.sticky")?H({hidden:!1}):Pa(e,t)).pipe(w(o=>r.next(o)),k(()=>r.complete()),l(o=>I({ref:e},o)))})}function Fa(e,{viewport$:t,header$:r}){let o=new Map,n=z("[href^=\\#]",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=ce(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(X("height"),l(({height:a})=>{let c=ye("main"),p=N(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),le());return xe(document.body).pipe(X("height"),v(a=>$(()=>{let c=[];return H([...o].reduce((p,[m,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,m]].reverse(),u)},new Map))}).pipe(l(c=>new Map([...c].sort(([,p],[,m])=>p-m))),Ge(i),v(([c,p])=>t.pipe(Cr(([m,f],{offset:{y:u},size:d})=>{let b=u+d.height>=Math.floor(a.height);for(;f.length;){let[,_]=f[0];if(_-p=u&&!b)f=[m.pop(),...f];else break}return[m,f]},[[],[...c]]),G((m,f)=>m[0]===f[0]&&m[1]===f[1])))))).pipe(l(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),V({prev:[],next:[]}),Ce(2,1),l(([a,c])=>a.prev.length{let i=new x,s=i.pipe(J(),ee(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[m]]of a.entries())m.classList.add("md-nav__link--passed"),m.classList.toggle("md-nav__link--active",p===a.length-1)}),te("toc.follow")){let a=M(t.pipe(ke(1),l(()=>{})),t.pipe(ke(250),l(()=>"smooth")));i.pipe(L(({prev:c})=>c.length>0),Ge(o.pipe(_e(ae))),oe(a)).subscribe(([[{prev:c}],p])=>{let[m]=c[c.length-1];if(m.offsetHeight){let f=or(m);if(typeof f!="undefined"){let u=m.offsetTop-f.offsetTop,{height:d}=he(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return te("navigation.tracking")&&t.pipe(K(s),X("offset"),ke(250),je(1),K(n.pipe(je(1))),Ot({delay:250}),oe(i)).subscribe(([,{prev:a}])=>{let c=fe(),p=a[a.length-1];if(p&&p.length){let[m]=p,{hash:f}=new URL(m.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Fa(e,{viewport$:t,header$:r}).pipe(w(a=>i.next(a)),k(()=>i.complete()),l(a=>I({ref:e},a)))})}function ja(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(l(({offset:{y:s}})=>s),Ce(2,1),l(([s,a])=>s>a&&a>0),G()),i=r.pipe(l(({active:s})=>s));return Q([i,n]).pipe(l(([s,a])=>!(s&&a)),G(),K(o.pipe(je(1))),ee(!0),Ot({delay:250}),l(s=>({hidden:s})))}function ei(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new x,s=i.pipe(J(),ee(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(K(s),X("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),ja(e,{viewport$:t,main$:o,target$:n}).pipe(w(a=>i.next(a)),k(()=>i.complete()),l(a=>I({ref:e},a)))}function ti({document$:e,tablet$:t}){e.pipe(v(()=>z(".md-toggle--indeterminate")),w(r=>{r.indeterminate=!0,r.checked=!1}),se(r=>h(r,"change").pipe($r(()=>r.classList.contains("md-toggle--indeterminate")),l(()=>r))),oe(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Wa(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function ri({document$:e}){e.pipe(v(()=>z("[data-md-scrollfix]")),w(t=>t.removeAttribute("data-md-scrollfix")),L(Wa),se(t=>h(t,"touchstart").pipe(l(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function oi({viewport$:e,tablet$:t}){Q([We("search"),t]).pipe(l(([r,o])=>r&&!o),v(r=>H(r).pipe(ze(r?400:100))),oe(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Ua(){return location.protocol==="file:"?ht(`${new URL("search/search_index.js",Qr.base)}`).pipe(l(()=>__index),B(1)):Ue(new URL("search/search_index.json",Qr.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var nt=Wo(),At=Qo(),gt=Bo(At),Yr=Ko(),Se=rn(),lr=Fr("(min-width: 960px)"),ii=Fr("(min-width: 1220px)"),ai=Go(),Qr=ue(),si=document.forms.namedItem("search")?Ua():Ve,Br=new x;Rn({alert$:Br});te("navigation.instant")&&In({location$:At,viewport$:Se}).subscribe(nt);var ni;((ni=Qr.version)==null?void 0:ni.provider)==="mike"&&Nn({document$:nt});M(At,gt).pipe(ze(125)).subscribe(()=>{Ke("drawer",!1),Ke("search",!1)});Yr.pipe(L(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ce("link[rel=prev]");typeof t!="undefined"&&ot(t);break;case"n":case".":let r=ce("link[rel=next]");typeof r!="undefined"&&ot(r);break;case"Enter":let o=Re();o instanceof HTMLLabelElement&&o.click()}});ti({document$:nt,tablet$:lr});ri({document$:nt});oi({viewport$:Se,tablet$:lr});var Xe=An(ye("header"),{viewport$:Se}),_t=nt.pipe(l(()=>ye("main")),v(e=>Hn(e,{viewport$:Se,header$:Xe})),B(1)),Na=M(...ne("consent").map(e=>an(e,{target$:gt})),...ne("dialog").map(e=>_n(e,{alert$:Br})),...ne("header").map(e=>Cn(e,{viewport$:Se,header$:Xe,main$:_t})),...ne("palette").map(e=>$n(e)),...ne("search").map(e=>Kn(e,{index$:si,keyboard$:Yr})),...ne("source").map(e=>Jn(e))),Da=$(()=>M(...ne("announce").map(e=>nn(e)),...ne("content").map(e=>Ln(e,{viewport$:Se,target$:gt,print$:ai})),...ne("content").map(e=>te("search.highlight")?Qn(e,{index$:si,location$:At}):T),...ne("header-title").map(e=>kn(e,{viewport$:Se,header$:Xe})),...ne("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?jr(ii,()=>Kr(e,{viewport$:Se,header$:Xe,main$:_t})):jr(lr,()=>Kr(e,{viewport$:Se,header$:Xe,main$:_t}))),...ne("tabs").map(e=>Xn(e,{viewport$:Se,header$:Xe})),...ne("toc").map(e=>Zn(e,{viewport$:Se,header$:Xe,main$:_t,target$:gt})),...ne("top").map(e=>ei(e,{viewport$:Se,header$:Xe,main$:_t,target$:gt})))),ci=nt.pipe(v(()=>Da),qe(Na),B(1));ci.subscribe();window.document$=nt;window.location$=At;window.target$=gt;window.keyboard$=Yr;window.viewport$=Se;window.tablet$=lr;window.screen$=ii;window.print$=ai;window.alert$=Br;window.component$=ci;})(); +//# sourceMappingURL=bundle.dff1b7c8.min.js.map + diff --git a/assets/javascripts/bundle.dff1b7c8.min.js.map b/assets/javascripts/bundle.dff1b7c8.min.js.map new file mode 100644 index 0000000..82d9023 --- /dev/null +++ b/assets/javascripts/bundle.dff1b7c8.min.js.map @@ -0,0 +1,8 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "src/assets/javascripts/bundle.ts", "node_modules/rxjs/node_modules/tslib/tslib.es6.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/assets/javascripts/browser/document/index.ts", "src/assets/javascripts/browser/element/_/index.ts", "src/assets/javascripts/browser/element/focus/index.ts", "src/assets/javascripts/browser/element/offset/_/index.ts", "src/assets/javascripts/browser/element/offset/content/index.ts", "src/assets/javascripts/utilities/h/index.ts", "src/assets/javascripts/utilities/round/index.ts", "src/assets/javascripts/browser/script/index.ts", "src/assets/javascripts/browser/element/size/_/index.ts", "src/assets/javascripts/browser/element/size/content/index.ts", "src/assets/javascripts/browser/element/visibility/index.ts", "src/assets/javascripts/browser/toggle/index.ts", "src/assets/javascripts/browser/keyboard/index.ts", "src/assets/javascripts/browser/location/_/index.ts", "src/assets/javascripts/browser/location/hash/index.ts", "src/assets/javascripts/browser/media/index.ts", "src/assets/javascripts/browser/request/index.ts", "src/assets/javascripts/browser/viewport/offset/index.ts", "src/assets/javascripts/browser/viewport/size/index.ts", "src/assets/javascripts/browser/viewport/_/index.ts", "src/assets/javascripts/browser/viewport/at/index.ts", "src/assets/javascripts/browser/worker/index.ts", "src/assets/javascripts/_/index.ts", "src/assets/javascripts/components/_/index.ts", "src/assets/javascripts/components/announce/index.ts", "src/assets/javascripts/components/consent/index.ts", "src/assets/javascripts/components/content/annotation/_/index.ts", "src/assets/javascripts/templates/tooltip/index.tsx", "src/assets/javascripts/templates/annotation/index.tsx", "src/assets/javascripts/templates/clipboard/index.tsx", "src/assets/javascripts/templates/search/index.tsx", "src/assets/javascripts/templates/source/index.tsx", "src/assets/javascripts/templates/tabbed/index.tsx", "src/assets/javascripts/templates/table/index.tsx", "src/assets/javascripts/templates/version/index.tsx", "src/assets/javascripts/components/content/annotation/list/index.ts", "src/assets/javascripts/components/content/annotation/block/index.ts", "src/assets/javascripts/components/content/code/_/index.ts", "src/assets/javascripts/components/content/details/index.ts", "src/assets/javascripts/components/content/mermaid/index.css", "src/assets/javascripts/components/content/mermaid/index.ts", "src/assets/javascripts/components/content/table/index.ts", "src/assets/javascripts/components/content/tabs/index.ts", "src/assets/javascripts/components/content/_/index.ts", "src/assets/javascripts/components/dialog/index.ts", "src/assets/javascripts/components/header/_/index.ts", "src/assets/javascripts/components/header/title/index.ts", "src/assets/javascripts/components/main/index.ts", "src/assets/javascripts/components/palette/index.ts", "src/assets/javascripts/integrations/clipboard/index.ts", "src/assets/javascripts/integrations/sitemap/index.ts", "src/assets/javascripts/integrations/instant/index.ts", "src/assets/javascripts/integrations/search/highlighter/index.ts", "src/assets/javascripts/integrations/search/worker/message/index.ts", "src/assets/javascripts/integrations/search/worker/_/index.ts", "src/assets/javascripts/integrations/version/index.ts", "src/assets/javascripts/components/search/query/index.ts", "src/assets/javascripts/components/search/result/index.ts", "src/assets/javascripts/components/search/share/index.ts", "src/assets/javascripts/components/search/suggest/index.ts", "src/assets/javascripts/components/search/_/index.ts", "src/assets/javascripts/components/search/highlight/index.ts", "src/assets/javascripts/components/sidebar/index.ts", "src/assets/javascripts/components/source/facts/github/index.ts", "src/assets/javascripts/components/source/facts/gitlab/index.ts", "src/assets/javascripts/components/source/facts/_/index.ts", "src/assets/javascripts/components/source/_/index.ts", "src/assets/javascripts/components/tabs/index.ts", "src/assets/javascripts/components/toc/index.ts", "src/assets/javascripts/components/top/index.ts", "src/assets/javascripts/patches/indeterminate/index.ts", "src/assets/javascripts/patches/scrollfix/index.ts", "src/assets/javascripts/patches/scrolllock/index.ts", "src/assets/javascripts/polyfills/index.ts"], + "sourceRoot": "../../..", + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2023 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantLoading,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up instant loading, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantLoading({ location$, viewport$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.component$ = component$ /* Component observable */\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n *\n * @class Subscription\n */\nexport class Subscription implements SubscriptionLike {\n /** @nocollapse */\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n * @return {void}\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n *\n * @class Subscriber\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @nocollapse\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param {T} [value] The `next` value.\n * @return {void}\n */\n next(value?: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param {any} [err] The `error` exception.\n * @return {void}\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n * @return {void}\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as (((value: T) => void) | undefined),\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent\n * @param subscriber The stopped subscriber\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n *\n * @class Observable\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @constructor\n * @param {Function} subscribe the function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @owner Observable\n * @method create\n * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor\n * @return {Observable} a new observable\n * @nocollapse\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @method lift\n * @param operator the operator defining the operation to take on the observable\n * @return a new observable with the Operator applied\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,\n * or the first of three possible handlers, which is the handler for each value emitted from the subscribed\n * Observable.\n * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.\n * @return {Subscription} a subscription reference to the registered handlers\n * @method subscribe\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next a handler for each value emitted by the observable\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @method Symbol.observable\n * @return {Observable} this instance of the observable\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n * @method pipe\n * @return {Observable} the Observable result of all of the operators having\n * been called in the order they were passed in.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @method toPromise\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @nocollapse\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return {Observable} Observable that the Subject casts to\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\n/**\n * @class AnonymousSubject\n */\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param bufferSize The size of the buffer to replay on subscription\n * @param windowTime The amount of time the buffered items will stay buffered\n * @param timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n *\n * @class Action\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler.\n * @return {void}\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n * @return {any}\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @class Scheduler\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return {number} A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param {function(state: ?T): ?Subscription} work A function representing a\n * task, or some unit of work to be executed by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler itself.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @return {Subscription} A subscription in order to be able to unsubscribe\n * the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @type {boolean}\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @type {any}\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n const flushId = this._scheduled;\n this._scheduled = undefined;\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an

+
+
    +
  • +

    Si no ha elegido una escena de referencia en particular, puede buscar escenas utilizando la búsqueda geográfica o por lista. La columna central tendrá un botón debajo de los metadatos titulado Herramienta Línea base para cualquier escena que sea elegible. Puede hacer clic en este botón para ser dirigido a una búsqueda de referencia. La búsqueda de Baseline usará la escena elegida como escena de referencia.

    +
  • +
  • +

    Si ha elegido una escena de referencia en particular, puede seleccionar Línea de base en la lista desplegable Tipo de búsqueda. Puede ingresar su escena de referencia y presionar Buscar.

    +
  • +
+

Interactuar con los resultados de búsqueda de referencia#

+

Mientras estés en el tipo de búsqueda de referencia, notará muchos controles familiares en el panel de resultados. Las escenas aparecen en la columna de la izquierda. Las líneas de base perpendiculares y temporales se enumeran al lado de cada escena. La columna central enumera los metadatos de la escena seleccionada e incluye el botón Línea base, que le permite configurar cualquier escena de la pila como escena de referencia. El gráfico de referencia aparece en la columna de la derecha.

+

Controles del panel de resultados

+
    +
  • En la parte superior izquierda del panel de resultados, verás la cantidad de escenas enumeradas.
  • +
  • Zoom hará Acercar los resultados ampliando el área del mapa de la Tierra donde se encuentran las escenas.
  • +
  • Lista podrá agregar todos los resultados a Descargas permitiéndole agregar todas las escenas a la lista de descargas.
  • +
  • On Demand le permitirá Agregar todos los resultados a la lista On Demand para realizar un procesamiento personalizado en las escenas. Para obtener más información, haga clic aquí.
  • +
  • Exportar le permitirá Descargar datos/metadatos para todas las escenas de la lista.
  • +
  • En la columna de la izquierda, Lista podrá agregar archivos de escena a las descargas solo para la escena seleccionada.
  • +
  • Debajo de los metadatos en la columna central, Línea base le permitirá establecer cualquier escena en la pila como escena de referencia. Cuando selecciones esto, tanto el gráfico como los valores de referencia se actualizarán automáticamente.
  • +
+

Controles de gráficos

+
    +
  • Los puntos en el gráfico representan escenas individuales. Al pasar el cursor sobre ellos, se enumerarán sus valores temporales y perpendiculares. También puede hacer clic en cualquier punto para seleccionar esa escena. Se actualizarán los metadatos de la columna central.
  • +
  • Ubicado encima del gráfico, encontrarás las etiquetas y los colores correspondientes. Estos indican cómo se muestran en el gráfico la escena de referencia, la escena seleccionada y cualquier escena en su lista de descarga. Algunos conjuntos de datos incluyen un área sombreada que indica la línea de base crítica.
  • +
  • Puede ampliar y desplazar el gráfico.
  • +
+

Criterios de referencia#

+
    +
  • Puede hacer clic en Criterios de referencia ... encima del gráfico para ver opciones adicionales.
      +
    • Puede ajustar los controles deslizantes para cambiar los valores perpendiculares y temporales que deseas incluir en tus resultados. +Búsqueda Estacional permite restringir los resultados a ciertos períodos anuales dentro de un rango general de fechas. Haga clic en el interruptor de Búsqueda Estacional y aparecerán opciones adicionales, permitiéndole ajustar los deslizadores para especificar un rango estacional (Día de Inicio de la Temporada/Día de Fin de la Temporada).
    • +
    • Puede ingresar una fecha de inicio y finalización.
    • +
    • Cambiar cualquier criterio actualizará automáticamente la lista de escenas y el gráfico.
    • +
    +
  • +
+

Próximos pasos#

+

Una vez que estés satisfecho con su conjunto de resultados, puede usar la lista de descarga para administrar y descargar los resultados de referencia. Puede encontrar más información sobre la lista de descarga en la Guía del usuario de introducción a Vertex.

+

Si quiere crear interferogramas, el procesamiento personalizado ahora está disponible a través de Vertex. Los detalles están disponibles en la sección Lista On Demand de la Guía del usuario de introducción a Vertex. Puede encontrar más información sobre la creación de interferogramas con el procesamiento personalizado de ASF a través de la documentación de HyP3.

+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/es/vertex/changelog/index.html b/es/vertex/changelog/index.html new file mode 100644 index 0000000..76d6839 --- /dev/null +++ b/es/vertex/changelog/index.html @@ -0,0 +1,1474 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Novedades - ASF SAR Manual de Búsqueda de Datos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Novedades#

+

¡Vertex ahora es multilingüe!#

+

Vertex ahora es compatible con inglés y español. Si el idioma de su navegador está configurado en español, Vértice usará español de forma predeterminada. También puede seleccionar su idioma preferido en el menú superior. Puede encontrar más información aquí.

+

Área de interés: Buscar una ubicación#

+

Ahora puede buscar un nombre de ubicación como su área de interés. El campo Buscar una ubicación se puede encontrar abriendo la ventana Área de interés. Puede encontrar más información aquí.

+

Nueva opción On Demand#

+

Los RTC de Sentinel-1 ahora pueden procesar con un espacio de píxeles de 10 metros. Puede encontrar más información aquí. Puede encontrar más información sobre la lista On Demand aquí.

+

Descargas mejoradas para Google Chrome#

+

La funcionalidad mejorada de lista de descargas está disponible en el navegador Google Chrome. Se incluyen indicadores de progreso de descarga y la opción de descargar todos los archivos en la lista. Descargar todo descargará 3 archivos simultáneamente hasta que se hayan descargado todos los archivos de la lista. Puede encontrar más información aquí.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/es/vertex/derived_datasets/index.html b/es/vertex/derived_datasets/index.html new file mode 100644 index 0000000..80006d4 --- /dev/null +++ b/es/vertex/derived_datasets/index.html @@ -0,0 +1,1550 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Conjuntos de Datos - ASF SAR Manual de Búsqueda de Datos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Tipo de Búsqueda de Conjuntos de Datos Derivados#

+

¿Qué son los Conjuntos de Datos Derivados?#

+

Los conjuntos de datos derivados son conjuntos de datos de nivel superior creados utilizando datos SAR. Los conjuntos de datos enumerados a continuación son la colección de ASF.

+

Conjunto de Datos de Coherencia e Retrodispersión Interferométrica Estacional Global Sentinel-1#

+

Este conjunto de datos es la representación espacial única en su tipo de firmas de coherencia e retrodispersión interferométrica multianual y global SAR en varias estaciones. La cobertura global abarca todas las masas terrestres y las capas de hielo desde 82 grados de latitud norte hasta 78 grados de latitud sur. El conjunto de datos se deriva del procesamiento interferométrico multitemporal de alta resolución de repetición de pasadas de unos 205,000 datos Sentinel-1 Single-Look-Complex (SLC) adquiridos en modo de banda ancha interferométrica (modo Sentinel-1 IW) desde el 1 de diciembre de 2019 hasta el 30 de noviembre de 2020. Más información se puede encontrar aquí.

+

Observatorio de Mapeo de Capas de Hielo Global (GISMO)#

+

El sistema radar espacial del Observatorio de Mapeo de Capas de Hielo Global (GISMO) es parte del Proyecto de Incubadora de Instrumentos de la NASA (IIP). GISMO se centra específicamente en medir la topografía de la superficie de las capas de hielo, el espesor de las capas de hielo y en descubrir propiedades físicas del lecho glaciar utilizando SAR. Utilizó radares interferométricos VHF y P-band y probó diferentes métodos de rechazo de interferencias. GISMO logró mapear las propiedades físicas del lecho glaciar a través de hasta 5 km de hielo. El proyecto GISMO documentó las líneas de vuelo sobre la capa de hielo de Groenlandia en 2006, 2007 y 2008. Más información se puede encontrar aquí.

+

Velocidad de Glaciares#

+

Este conjunto de datos fue producido por Evan Burgess y sus colegas de la Universidad de Utah y la Universidad de Alaska Fairbanks utilizando datos ALOS PALSAR. Revela patrones complejos de flujo de glaciares en todo Alaska. Los datos de velocidad están disponibles para su descarga en formatos diseñados tanto para científicos como para educadores. Las velocidades superficiales están disponibles para 47,880 km^2 de hielo glaciar, lo que incluye casi todos los glaciares principales del estado. Información detallada sobre su producción está disponible en Burgess et al., Nature Communications, 2013. Más información se puede encontrar aquí.

+

Año Polar Internacional#

+

El Año Polar Internacional (IPY) es un evento de investigación colaborativa centrado en el Ártico y la Antártida. El IPY 2007-2009 se centró en la investigación colaborativa y exploró extensamente las complejas relaciones entre el Ártico y la Antártida. Más de 60 países y miles de investigadores participaron, investigando más de 200 proyectos. Los temas incluyen las relaciones del Ártico y la Antártida con elementos geofísicos, océanos y hielo marino, la atmósfera de la Tierra, el espacio y las relaciones humanas. ASF alberga un archivo del proyecto IPY titulado el Año Polar Global Interagencia de Instantáneas Polares IPY (GIIPSY). El objetivo de GIIPSY era obtener instantáneas de satélite de alta definición de las regiones polares durante 2007-2008. Más información se puede encontrar aquí.

+

Proyecto de Mapeo Antártico RADARSAT-1 (RAMP)#

+

El Proyecto de Mapeo Antártico RADARSAT-1 (RAMP) se compone de dos misiones principales, la primera Misión de Mapeo Antártico (AMM-1) y la Misión de Mapeo Antártico Modificada (MAMM). AMM-1 comenzó el 9 de septiembre de 1997 y se completó el 20 de octubre de 1997. Sus objetivos eran adquirir un mapa completo de la Antártida y comprender mejor las relaciones entre los elementos ambientales del continente más al sur. MAMM comenzó el 3 de septiembre de 2000 y se completó el 17 de noviembre de 2000. Planeaba volver a cartografiar la Antártida y medir datos de velocidad del hielo mediante análisis interferométricos y datos de AMM-1. Más información se puede encontrar aquí.

+

MEaSUREs de Hielo Marino#

+

Las imágenes y productos de datos de hielo marino son respaldados por el programa Making Earth System data records for Use in Research Environments (MEaSUREs) de la NASA. Las imágenes, datos y productos de datos del Ártico y el Océano Austral están disponibles sin costo para usuarios aprobados por el ASF DAAC. Estos incluyen más de 11 años de imágenes de radar de tres días de RADARSAT-1 del hielo marino del Ártico y el Océano Austral, y imágenes SAR originales. Los datos de RADARSAT-1 se han procesado para construir un registro casi decenal del movimiento del hielo a pequeña escala del Ártico y el Océano Austral, un registro del movimiento del hielo del Mar de Bering del norte y mosaicos de imágenes de alta resolución mensuales del Océano Ártico. Más información se puede encontrar aquí.

+

MEaSUREs de Humedales#

+

El Registro de Datos del Sistema Terrestre Inundado (ESDR) de humedales consta de dos componentes principales. En primer lugar, mapas de alta resolución de la extensión de humedales, el tipo de vegetación y la dinámica de inundación estacional, derivados de SAR, para áreas a nivel regional y continental que cubren sistemas de humedales cruciales. En segundo lugar, series temporales de mapeos de la fracción de área inundada a nivel global de resolución gruesa de ~25 km derivados de múltiples observaciones de teledetección por satélite, incluidos sensores de microondas activos y pasivos y conjuntos de datos ópticos optimizados para la detección de inundaciones. Estos conjuntos de datos se proporcionan cada dos meses para el período 1992-1999 y diariamente a partir de 2000 en adelante. También se proporcionan productos resumidos anuales y un conjunto de datos de tiempo real casi diario (NRT) con una latencia de 2-3 días. Más información se puede encontrar aquí.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/es/vertex/events/index.html b/es/vertex/events/index.html new file mode 100644 index 0000000..f38430f --- /dev/null +++ b/es/vertex/events/index.html @@ -0,0 +1,1596 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Evento - ASF SAR Manual de Búsqueda de Datos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Tipo de Búsqueda de Eventos#

+

¿Qué es la Búsqueda de Eventos?#

+

La búsqueda de eventos aprovecha las capacidades del procesamiento SAR para monitorear desastres naturales. Los peligros actualmente admitidos son erupciones volcánicas y terremotos. Los productos generados incluyen series temporales de imágenes completamente corregidas en cuanto al terreno, así como datos SAR interferométricos sobre áreas afectadas por desastres naturales. Para facilitar la automatización completa, el flujo de procesamiento se desencadena automáticamente mediante sistemas de alerta de peligro existentes, como el Servicio de Notificación de Terremotos del USGS. El monitoreo de eventos a través de Vertex se basa en la tecnología desarrollada dentro de SARVIEWS a través de la subvención NNX12AQ38G. Visita la documentación de Eventos (SARVIEWS) para obtener más información.

+

Cómo usar la Búsqueda de Eventos de Vertex#

+

Visita Vertex de ASF para comenzar a usar la búsqueda de eventos.

+

Comenzando su Búsqueda de Eventos#

+
    +
  • Cuando seleccionas el tipo de búsqueda Evento, se realizará una búsqueda y se mostrarán todos los eventos disponibles. Al igual que con otros tipos de búsqueda, hay filtros disponibles para limitar o refinar tus resultados de búsqueda.
  • +
  • Haga clic en Búsqueda de Evento para ingresar un nombre de evento o un nombre parcial. También puede seleccionar el evento deseado en la lista desplegable que se muestra cuando haces clic en el campo.
  • +
  • Bajo Tipos de Eventos, puede elegir qué tipos de eventos deseas que se muestren. Actualmente, hay eventos de Terremotos y Volcanes.
  • +
  • Puede seleccionar una Fecha de Inicio o una Fecha de Finalización.
  • +
  • Haga clic en Filtros para más opciones.
      +
    • Puede activar o desactivar el interruptor de Solo Eventos Activos para mostrar solo eventos activos. El valor predeterminado es mostrar todos los eventos, incluidos los eventos inactivos.
    • +
    • Puede ajustar el control deslizante de Magnitud para filtrar terremotos según el rango de magnitud deseado. Nota: Este filtro se aplica solo a eventos de terremotos. Si su búsqueda incluye volcanes, estos seguirán apareciendo en tus resultados de búsqueda.
    • +
    +
  • +
  • Una vez que hayas seleccionado tus filtros deseados, haga clic en Buscar para actualizar tus resultados de búsqueda.
  • +
+

Filtros de Productos#

+
    +
  • Los Filtros de Ruta y Cuadro están disponibles. Puede ingresar una sola ruta o cuadro o un rango.
      +
    • Haga clic en Limpiar para borrar los valores de ruta y cuadro ingresados.
    • +
    • Ten en cuenta que Ruta y Cuadro filtrarán los productos mostrados dentro de cada evento.
    • +
    +
  • +
  • Bajo Tipo de Producto, puede seleccionar uno o más tipos de productos. Esto filtrará los productos mostrados dentro de cada evento.
  • +
+

Interacción con los Resultados de la Búsqueda de Eventos#

+

Mientras estás en el tipo de búsqueda de eventos, notarás muchos controles familiares en el panel de resultados. Los eventos se muestran en la columna izquierda. Los íconos de Volcán y Terremoto indican qué tipo de evento es cada resultado. La columna central enumera los detalles y metadatos del evento seleccionado. Los archivos para el evento seleccionado se muestran en la columna derecha.

+

Controles del Panel de Resultados

+
    +
  • En la parte superior izquierda del panel de resultados, verás el número de eventos devueltos por su búsqueda.
  • +
  • Zoom ampliará el área del mapa de la Tierra donde se encuentra el evento.
  • +
  • Lista agregará todos los resultados a las descargas, lo que te permite agregar todos los productos del evento a la lista de descarga.
      +
    • Puede optar por agregar Todos los Productos del Evento o Productos del Evento Seleccionados a la lista de descarga. Puede seleccionar archivos individuales en la columna derecha.
    • +
    +
  • +
  • Exportar descargará el Script de Descarga a Granel. Este script en Python te permite descargar todos los productos de la escena seleccionada.
  • +
  • Bajo Demanda te permitirá agregar todos los resultados a la lista de Bajo Demanda para procesamiento personalizado de las escenas. Dependiendo de los tipos de archivos asociados con el evento elegido, es posible que puedas agregar trabajos RTC o InSAR a su lista. Para obtener más información, haga clic aquí.
  • +
  • Copiar te permite copiar los ID de Escena o las URL de Descarga.
      +
    • Puede optar por copiar Todos los ID de Escena o URL, o solo copiar ID de Escena o URL Seleccionados. Puede seleccionar archivos individuales en la columna derecha.
    • +
    +
  • +
  • La columna de Eventos (izquierda).
      +
    • Cada evento tiene un ícono de terremoto o volcán a la izquierda para ayudarte a identificar rápidamente el tipo de evento.
    • +
    • Haga clic en Zoom al Evento para ampliar el área del mapa de la Tierra donde se encuentra el evento.
    • +
    +
  • +
  • +

    La columna de Detalle del Evento (centro).

    +
      +
    • Los detalles del evento se enumeran aquí. Esto incluye el tiempo de inicio y finalización del procesamiento del evento. Para los terremotos, también se muestra la magnitud y la profundidad.
    • +
    • Puede Copiar el ID del Evento.
    • +
    • Para eventos de terremotos, se muestra el ID del USGS. Para los volcanes, se muestra el ID del Smithsonian. Haga clic en el enlace para ir a la página de eventos del USGS o del Smithsonian.
    • +
    • Ajusta el control deslizante de Escala del Polígono de Búsqueda Geográfica según lo desees. El polígono de Área de Interés también se actualizará en el mapa.
    • +
    • Una vez que estés satisfecho con la Escala del Polígono de Búsqueda Geográfica, Haga clic en Geográfica para iniciar una búsqueda geográfica utilizando el Área de Interés y las fechas del evento.
    • +
    • Haga clic en Lista para iniciar una búsqueda de lista que incluye todas las escenas de productos del evento.
    • +
    +
  • +
  • +

    El ícono del ojo etiquetado como Abrir en Visor de Imágenes abre una ventana de vista previa más grande.

    +
      +
    • Nota: Al ver imágenes InSAR en el visor de imágenes, se muestra la imagen de vista previa envuelta. La imagen de vista previa sin envolver está disponible en el producto descargado.
    • +
    • En el visor de vista previa, amplía usando los botones + o -. También puede hacer zoom y panoramizar con el mouse.
    • +
    • Haga clic o desplázate por las miniaturas en la parte inferior para ver otras imágenes de vista previa para el evento seleccionado.
    • +
    • Los metadatos de la escena se enumeran en el lado derecho de la ventana del visor de vista previa.
    • +
    • Bajo Archivo, puede hacer clic en el botón etiquetado RTC GAMMA o INSAR GAMMA para obtener más opciones.
        +
      • Haga clic en Descargar Archivo para descargar el producto seleccionado.
      • +
      • Haga clic en Agregar archivo a la lista para agregarlo a su lista de descarga.
      • +
      • Haga clic en Escenas de Referencia para copiar los nombres de las escenas de referencia al portapapeles. Estos pueden guardarse en un archivo o utilizarse en una Búsqueda de Lista.
      • +
      • Haga clic en Anclar Vista Previa al Mapa para anclar la imagen de vista previa al mapa. Una vez anclada, puede hacer clic en este botón nuevamente para desanclarla.
      • +
      +
    • +
    • Haga clic en el ícono Descargar esta imagen para descargar la imagen de vista previa.
    • +
    • Haga clic en el ícono Anclar para anclar la imagen de vista previa seleccionada al mapa. Una vez anclada, puede hacer clic en este botón nuevamente para desanclarla.
    • +
    +
  • +
  • La columna de Archivos (derecha).
      +
    • El número total de archivos para el evento seleccionado se muestra en esta columna.
    • +
    • Puede ordenar los archivos usando los botones Ordenar por y Orden en la parte superior de la columna.
        +
      • Bajo Ordenar por, puede elegir Fecha, Ruta o Cuadro.
      • +
      • Haga clic en la Flecha de Orden para alternar entre orden ascendente y descendente.
      • +
      +
    • +
    • Haga clic en Criterios de Producto para abrir los Filtros de Búsqueda.
    • +
    • Haga clic en las casillas de verificación junto a cada archivo para seleccionarlo o deseleccionarlo. Los archivos seleccionados se anclarán en el mapa. Una vez que hayas seleccionado los archivos deseados, también puede usar los controles Descargar o Copiar en la parte superior izquierda del panel de resultados para interactuar con los productos seleccionados.
    • +
    • Haga clic en Bajo Demanda para agregar el archivo seleccionado a su lista de Bajo Demanda para procesamiento adicional.
    • +
    • Haga clic en el ícono del Carrito de Compras para agregar el archivo seleccionado a su lista de Descarga.
    • +
    • Haga clic en Descargar para descargar el archivo seleccionado.
    • +
    • Nota: Debe iniciar sesión para descargar productos.
    • +
    +
  • +
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/es/vertex/manual/index.html b/es/vertex/manual/index.html new file mode 100644 index 0000000..4518f70 --- /dev/null +++ b/es/vertex/manual/index.html @@ -0,0 +1,2114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Guía del Usuario para Comenzar con Vertex - ASF SAR Manual de Búsqueda de Datos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Guía del Usuario para Comenzar con Vertex#

+
    +
  • Si aún no tiene una cuenta, cree una cuenta gratuita de Inicio de sesión de Earthdata.
  • +
  • Vaya a Vertex
  • +
  • Inicie sesión haciendo clic en el icono de Iniciar sesión en la parte superior derecha de la ventana. Utilice su nombre de usuario y contraseña de Earthdata. +
  • +
  • El Tipo de Búsqueda le permite elegir entre todos los tipos de búsqueda disponibles.
  • +
+

Opciones de Idioma#

+

En el menú superior derecho, junto al icono de Iniciar sesión, hay opciones de control de idioma. Vertex actualmente ofrece inglés y español. Si su navegador está configurado en uno de los idiomas disponibles, Vertex predeterminará ese idioma. Puede hacer clic en el botón y seleccionar su idioma deseado de la lista desplegable. También puede establecer un idioma predeterminado en sus Preferencias.

+

Opciones de Búsqueda Geográfica#

+

+
    +
  • En la esquina superior izquierda del mapa, hay botones que le permiten cambiar su vista del mapa, zoom y capas.
  • +
  • De manera predeterminada, el mapa está en proyección ecuatorial. Puede hacer clic en Vista de Mapa y seleccionar Vista de mapa Ártico o Vista de mapa Antártico para cambiar su proyección de mapa. Haga clic en Vista de mapa Ecuatorial para volver a la proyección ecuatorial.
  • +
  • Puede hacer clic en los iconos de Acercar o Alejar para ajustar su zoom.
  • +
  • La capa de mapa predeterminada es satelital. Puede hacer clic en el botón Capas y seleccionar Vista Satelital o Vista de Calle para cambiar su capa de mapa.
      +
    • Puede hacer clic en Mapa de Vista General para agregar un mapa de vista general en la esquina superior derecha del mapa. Haga clic nuevamente para apagar el mapa de vista general.
    • +
    • Puede hacer clic en Capa de Coherencia para seleccionar una capa de coherencia estacional. Haga clic en el círculo junto a la estación que desee activar. Haga clic nuevamente en la casilla de verificación de la Capa de Coherencia para desactivar la capa.
    • +
    • Puede hacer clic en Líneas de Cuadrícula para agregar una superposición de retícula al mapa. Haga clic nuevamente para desactivar la superposición. Nota: Esto actualmente solo está disponible en la vista de mapa ecuatorial.
    • +
    +
  • +
  • Puede hacer clic en Opacidad y ajustar el control deslizante según lo desee para cambiar la opacidad de las imágenes de navegación que se muestran en el mapa. Si la Capa de Coherencia está activada, también puede ajustar la opacidad de esa capa.
  • +
  • Navegue a su área de interés arrastrando el mapa mientras mantiene presionado el botón izquierdo del ratón.
  • +
  • De manera predeterminada, la herramienta de dibujo de mapas es un cuadro delimitador. Haga clic una vez en el mapa para especificar la esquina inicial, mueva el ratón y luego haga clic nuevamente para terminar el cuadro. Hay opciones adicionales de herramientas de dibujo disponibles en la barra de herramientas en la parte superior de la pantalla, incluidas las opciones de punto, línea y polígono.
  • +
  • Punto le permite definir un área de interés haciendo clic en el mapa para colocar un punto.
  • +
  • Línea le permite definir un área de interés sobre una serie de segmentos de línea haciendo clic varias veces en el mapa. Haga doble clic para dejar de agregar segmentos.
  • +
  • Polígono le permite definir un área de interés sobre un polígono arbitrario. Recibirá un mensaje de error en la parte inferior de la ventana si hay un problema con el polígono (autointersección, orden de enrollado del polígono invertido, etc.).
  • +
  • Cuadro le permite definir un área de interés sobre un cuadro delimitador alineado con latitud/longitud haciendo clic una vez para establecer una esquina y nuevamente para establecer la esquina opuesta.
  • +
  • Círculo le permite definir un área de interés sobre un círculo arbitrario. Haga clic y arrastre para seleccionar su círculo. Haga clic nuevamente para dejar de dibujar.
  • +
  • Una vez que se haya dibujado una forma, seleccione el icono Editar área de interés actual en la barra de herramientas para mover, agregar y eliminar puntos. Seleccione el icono Dibujar nueva área de interés para crear una nueva AOI.
  • +
  • Hacer clic en Cargar Archivo Geoespacial abre la ventana de diálogo del Área de Interés. Puede ingresar una cadena WKT, cargar un archivo geoespacial o ingresar una ubicación.
  • +
  • Conjunto de Datos le permite elegir el conjunto de datos de interés.
  • +
  • Si necesita más información sobre un conjunto de datos en particular, haga clic en el icono de signo de interrogación correspondiente en el selector de Conjunto de Datos.
  • +
  • Filtros... le permite refinar aún más su búsqueda
  • +
+

Opciones de Área de Interés#

+
    +
  • Área de Interés le da la opción de ingresar un conjunto de coordenadas geográficas, importar un área de interés como un archivo geoespacial o buscar una ubicación. Haga clic en la flecha hacia abajo junto a Área de Interés en el menú superior.
  • +
  • Un área de interés puede definirse mediante un conjunto de coordenadas ingresadas en la ventana de Área de Interés WKT.
      +
    • Las coordenadas deben ingresarse como grados decimales en formato de texto bien conocido (WKT). Las coordenadas ingresadas como una cadena de longitud/latitud separada por comas (por ejemplo, -97.38,36.46,-53.44,36.46...) serán convertidas automáticamente por Vertex al formato WKT.
    • +
    +
  • +
  • Para cargar un archivo geoespacial, haga clic en Seleccionar Archivos y navegue a una carpeta en su computadora, o arrastre y suelte archivos en el cuadro. Se admiten archivos GeoJSON, shapefiles y KML siempre que estén en un sistema de coordenadas basado en latitud/longitud, como WGS84.
      +
    • Al importar un archivo GeoJSON, se incluirán todas las geometrías en el archivo. Si se encuentran múltiples geometrías, se utilizará un casco convexo para representarlas en la búsqueda.
    • +
    • Los shapefiles pueden ser un solo archivo .shp, múltiples componentes de shapefile (.shp, .shx, .dbf) o un archivo zip que contenga uno o más componentes de shapefile. Como mínimo, el componente .shp debe estar incluido en todos los casos.
    • +
    +
  • +
  • Para ingresar una ubicación, haga clic en el campo Buscar una Ubicación y comience a escribir el nombre de la ubicación. Seleccione la ubicación deseada de la lista desplegable.
      +
    • Una vez que haya seleccionado una ubicación, se codificará en coordenadas de formato WKT.
    • +
    +
  • +
  • Puede guardar las coordenadas de una búsqueda para que se puedan usar para recrear exactamente un área de interés en búsquedas posteriores.
      +
    • Una vez que se haya establecido el Área de Interés, aparecerá un icono de Copiar al portapapeles. Haga clic en el icono y pegue las coordenadas en una nueva búsqueda o en un archivo de texto para usarlas más tarde.
    • +
    • Nota: Consulte la sección Otras Opciones de Vertex para obtener formas adicionales de guardar búsquedas.
    • +
    +
  • +
  • En cualquier momento, puede borrar su área de búsqueda haciendo clic en el botón Borrar.
  • +
+

Validación de Forma#

+

Si el AOI especificado es su propio Rectángulo Mínimo Delimitador (MBR) en una proyección mercator, los resultados de la búsqueda devueltos se intersectarán con el AOI en una proyección mercator, independientemente de su ancho. Esto sigue siendo el caso incluso si la línea internacional de cambio de fecha se cruza dentro del AOI.

+

Para que un AOI se considere su propio MBR, debe cumplir con los siguientes criterios:

+
    +
  • Cada vértice comparte una latitud o longitud con sus vecinos
  • +
  • Los puntos Este/Oeste comparten longitud
  • +
  • Los puntos Norte/Sur comparten latitud
  • +
+

Los AOI que no cumplan con estos criterios tendrán sus puntos conectados a lo largo de círculos máximos.

+

Además, todos los AOI se validan y luego se simplifican según sea necesario. El proceso para esto es:

+
    +
  1. Validar el AOI de entrada. Si no es válido, se muestra un error.
  2. +
  3. Fusionar formas superpuestas.
  4. +
  5. Casco convexo.
  6. +
  7. Cualquier valor de índice fuera de rango se maneja ajustándolos y envolviéndolos al rango válido de valores.
  8. +
  9. Simplificar puntos en función del umbral de proximidad. El objetivo es menos de 400 puntos.
  10. +
+

Cada uno de estos pasos se realiza solo cuando es necesario para llevar el AOI a un solo contorno con menos de 400 puntos. Cualquier paso innecesario se omite.

+

Ejemplos de validación y simplificación:

+
    +
  • Se proporciona un polígono que se autointersecta:
  • +
  • Se muestra un error.
  • +
  • Se proporciona un solo contorno, que consta de 1000 puntos:
  • +
  • Se utiliza una versión simplificada del mismo contorno, que consta de menos de 400 puntos.
  • +
  • Se proporcionan múltiples geometrías, todas ellas al menos en parte superpuestas:
  • +
  • Se devuelve un solo contorno, que representa el contorno de todas las formas combinadas.
  • +
  • Se proporcionan múltiples geometrías, al menos algunas de ellas completamente no superpuestas:
  • +
  • Se devuelve un solo contorno, que representa el casco convexo de todas las formas juntas.
  • +
+

Filtros de Fecha#

+
    +
  • Filtros de Fecha Las fechas de búsqueda son opcionales, por lo que de manera predeterminada están vacías. Si está buscando fechas específicas, puede definir el rango de fechas en los campos de Fecha de Inicio y Fecha de Fin. El selector de fechas limitará automáticamente su selección a un rango válido para el conjunto de datos seleccionado.
  • +
  • Nota: Esta información también se puede encontrar haciendo clic en el icono de signo de interrogación para un conjunto de datos.
  • +
  • Búsqueda Estacional permite restringir la búsqueda a ciertos períodos anuales dentro de un rango general de fechas. Haga clic en el interruptor de Búsqueda Estacional y aparecerán opciones adicionales, que le permitirán ingresar un rango general de fechas (Fecha de Inicio/Fecha de Fin) y el rango estacional (Día de Inicio de la Estación/Día de Fin de la Estación).
  • +
+

Filtros Adicionales#

+

+
    +
  • Filtros Adicionales permiten aplicar parámetros adicionales para estrechar su búsqueda y reducir el número de resultados. No todos los filtros estarán disponibles para todos los conjuntos de datos.
  • +
  • Tipo de Archivo – Limitar la búsqueda a tipos específicos de archivos. Se permiten múltiples selecciones.
  • +
  • Modo de Haz – Limitar la búsqueda a modos específicos de haz. Se permiten múltiples selecciones.
  • +
  • Polarización – Limitar la búsqueda a polarizaciones específicas. Se permiten múltiples selecciones.
  • +
  • Dirección – Limitar la búsqueda a una dirección de órbita específica.
  • +
  • Subtipo – Limitar la búsqueda a una nave espacial de misión específica.
  • +
  • ID de Grupo – Limitar la búsqueda a un ID de grupo específico.
  • +
  • ID de Ráfaga – Limitar la búsqueda a un ID de ráfaga específico. Se permiten múltiples ID de ráfaga.
  • +
  • Productos Estándar o Productos CalVal – Limitar la búsqueda a productos CalVal o Estándar. Puede elegir una opción. Este selector solo está disponible para el conjunto de datos Opera-S1.
  • +
  • Selector de Campaña – Limitar la búsqueda a una campaña específica.
  • +
+

Filtros de Ruta y Cuadro#

+
    +
  • Filtros de Ruta y Cuadro están disponibles para conjuntos de datos seleccionados. Puede ingresar una sola ruta o cuadro, o un rango. Debido a la inconsistencia del encuadre de Sentinel-1, recomendamos buscar un cuadro de interés con un margen de ±1-2 cuadros.
  • +
+

Opciones de Búsqueda Adicionales#

+
    +
  • El número máximo de resultados se muestra debajo del botón BUSCAR. Haga clic en la flecha hacia abajo para elegir su número máximo de resultados preferido.
  • +
  • Para borrar todos los filtros de búsqueda actuales, haga clic en la flecha hacia abajo junto al botón BUSCAR, luego haga clic en Borrar Búsqueda.
  • +
  • Una vez que se hayan elegido todos los parámetros, haga clic en BUSCAR. Los resultados de la búsqueda aparecerán en el área del pie de la ventana de Vertex y en el mapa.
  • +
  • Nota: El número de archivos que se predice que coincidirán con los parámetros de búsqueda actuales se muestra debajo del botón BUSCAR. Si no hay coincidencias previstas, el botón de búsqueda estará desactivado y mostrará SIN RESULTADOS.
  • +
+

Opciones de Búsqueda de Lista#

+

+
    +
  • Seleccionar Búsqueda de Lista abre la ventana de Búsqueda de Lista y le permite ingresar una lista de escenas o nombres de archivos.
  • +
  • Escena permite buscar nombres de escenas específicos (nombres de granulo), y los resultados incluirán cualquier archivo que sea parte de esas escenas.
  • +
  • Archivo permite buscar nombres de archivos específicos (nombres de productos), y los resultados solo incluirán exactamente esos archivos.
  • +
  • Editar Lista abre la ventana de Búsqueda de Lista para que pueda hacer cambios en su lista.
  • +
  • Una vez que se hayan elegido todos los parámetros, haga clic en BUSCAR. Los resultados de la búsqueda aparecerán en el área del pie de la ventana de su navegador y en el mapa.
  • +
  • Nota: El número de archivos que se predice que coincidirán con los parámetros de búsqueda actuales se muestra debajo del botón BUSCAR. Si no hay coincidencias previstas, el botón de búsqueda estará desactivado y mostrará SIN RESULTADOS.
  • +
+

Importación de Archivos de Búsqueda de Lista#

+

Puede arrastrar y soltar archivos en el cuadro proporcionado en las pestañas Escena o Archivo. Cada pestaña enumera los tipos de archivos aceptados en la parte inferior. Vertex analizará los nombres de las escenas o archivos de su archivo cargado.

+
    +
  • +

    Nota: Cada tipo de archivo requiere un formato específico. Los archivos exportados desde Vertex tendrán el formato correcto.

    +
  • +
  • +

    CSV requiere una columna etiquetada como "Nombre del Granulo" para una búsqueda de lista de escenas. Requiere una columna adicional "Nivel de Procesamiento" para una búsqueda de lista de archivos.

    +
  • +
  • GeoJSON requiere un campo etiquetado como "granuleName" para la búsqueda de lista de escenas. Requiere un campo etiquetado como "fileID" para la búsqueda de lista de archivos.
  • +
  • Metalink requiere una estructura con el siguiente formato
  • +
+
<metalink>
+    <files>
+        <file name="[Scene-Name.zip]"></file>
+        <file name ="...
+        ...</file>
+    </files>
+</metalink>
+
+
    +
  • KML requiere una estructura con el siguiente formato
  • +
+
<kml>
+    <Document>
+        <Placemark>
+            <name>[Scene Name]</name>
+        </Placemark>
+    </Document>
+</kml>
+
+

Opciones de Búsqueda Línea base#

+

+
    +
  • Seleccionar Búsqueda Línea base proporciona un espacio para ingresar el nombre de una Escena de Referencia y luego buscará todas las escenas secundarias que coincidan con el área de cobertura de la Referencia.
  • +
  • Nota: Si no hay escenas coincidentes, el botón de RESULTADOS estará desactivado y mostrará SIN RESULTADOS.
  • +
  • Una vez que se haya ingresado una Escena de Referencia, haga clic en BUSCAR. Los resultados de la búsqueda aparecerán debajo del mapa. Hacer clic en el icono de Acercar a los resultados en la parte superior de la columna de resultados de la izquierda mostrará la ubicación del conjunto de escenas en el mapa.
  • +
  • El gráfico muestra la relación Temporal y Perpendicular (espacial) de las escenas secundarias con la Referencia.
  • +
  • El botón Criterios Línea base... le permite especificar criterios adicionales para refinar sus resultados, como fechas de inicio y fin, configuraciones de fechas estacionales y extensiones temporales y perpendiculares.
  • +
  • Para obtener más información sobre Línea base, consulte la documentación de Baseline.
  • +
+

Opciones de Búsqueda SBAS#

+

+
    +
  • Seleccionar Búsqueda SBAS proporciona un espacio para ingresar el nombre de una Escena de Referencia y buscará todas las escenas secundarias que coincidan con el área de cobertura de la Referencia. Es un método alternativo utilizado para el procesamiento SAR Interferométrico (InSAR), similar a Línea base.
  • +
  • Nota: Si no hay escenas coincidentes, el botón de RESULTADOS estará desactivado y mostrará SIN RESULTADOS.
  • +
  • Una vez que se haya ingresado una Escena de Referencia, haga clic en BUSCAR. Los resultados de la búsqueda aparecerán debajo del mapa. Hacer clic en el icono de Acercar a los resultados en la parte superior de la columna de resultados de la izquierda mostrará la ubicación del conjunto de escenas en el mapa.
  • +
  • El gráfico muestra la relación Temporal y Perpendicular (espacial) de las escenas secundarias con la Referencia.
  • +
  • Los botones Acercar y Alejar están disponibles encima del gráfico.
  • +
  • El botón Ajustar al Tamaño asegura que todos los pares sean visibles en el gráfico.
  • +
  • Los botones Par Personalizado le permiten agregar o eliminar un par personalizado.
  • +
  • El botón Criterios SBAS... le permite especificar criterios adicionales para refinar sus resultados, como fechas de inicio y fin, configuraciones de fechas estacionales y configuraciones del umbral de superposición latitudinal.
  • +
  • Para obtener más información sobre SBAS, consulte la documentación de SBAS.
  • +
+

Opciones de Búsqueda Event#

+
    +
  • Seleccionar Evento le permite ver y buscar los productos creados para la monitorización de peligros.
  • +
  • Búsqueda de Evento le permite ingresar el nombre de un evento. Puede ingresar el nombre completo o una cadena parcial.
  • +
  • Tipos de Evento le permite filtrar los tipos de eventos que desea ver. Actualmente, hay eventos de terremotos y volcanes.
  • +
  • Fecha de Inicio y Fecha de Fin le permiten especificar un rango de fechas para los eventos.
  • +
  • Opciones adicionales se pueden encontrar en Filtros.
  • +
  • Puede alternar el interruptor de Solo Eventos Activos para mostrar solo eventos activos. De manera predeterminada, se muestran todos los eventos, incluidos los eventos inactivos.
  • +
  • Puede ajustar el control deslizante de Magnitud para filtrar terremotos por el rango de magnitud deseado. Nota: Este filtro se aplica solo a eventos de terremotos. Si su búsqueda incluye volcanes, estos continuarán apareciendo en los resultados de la búsqueda.
  • +
  • Para obtener más información sobre la búsqueda de Eventos, consulte la documentación de Búsqueda de Eventos.
  • +
+

Opciones de Búsqueda Productos a Demanda#

+
    +
  • Seleccionar Productos a Demanda le permite ver sus trabajos a demanda enviados. Nota: Debe iniciar sesión para acceder a esto. Si no ha iniciado sesión, esta opción de búsqueda estará desactivada y no podrá seleccionarla.
  • +
  • Nombre del Proyecto le permite limitar su búsqueda a un nombre de proyecto específico. A medida que comience a escribir, se mostrarán opciones de autocompletado con los nombres de proyectos que ha utilizado anteriormente.
  • +
  • Filtros de Fecha Las fechas de búsqueda son opcionales, por lo que de manera predeterminada están vacías. Si está buscando fechas específicas, puede definir el rango de fechas en los campos de Fecha de Inicio y Fecha de Fin. Nota: Estas fechas se filtran por la fecha de la escena, no por la fecha en que se procesó.
  • +
  • Producto/Escena de Origen le permite ingresar el nombre del producto o el nombre de la escena de origen para limitar su búsqueda. Este campo también aceptará una cadena parcial del producto o la escena de origen en lugar del nombre completo.
  • +
  • Estado del Trabajo le permite limitar su búsqueda a estados específicos. Se permiten múltiples selecciones.
  • +
  • Nota: Los trabajos expiran 14 días después de enviarlos. Los productos expirados aún aparecen en los resultados de búsqueda, sin embargo, ya no podrá descargarlos ni agregarlos a su carrito. Puede identificar fácilmente sus productos expirados por la etiqueta Expirado junto al nombre del producto.
  • +
  • Para obtener más información sobre Productos a Demanda, consulte la documentación.
  • +
+

Opciones de Búsqueda Derived Datasets#

+
    +
  • Seleccionar Conjuntos de Datos Derivados le permite ver y descargar productos del catálogo de conjuntos de datos de ASF.
  • +
  • Cada conjunto de datos listado incluye una breve descripción.
  • +
  • Haga clic en Más Información para ver más información sobre el conjunto de datos.
  • +
  • Haga clic en Descargar para ver y descargar productos disponibles para el conjunto de datos elegido. Nota: El enlace de descarga se abrirá en una nueva ventana del navegador.
  • +
  • Para obtener más información sobre Conjuntos de Datos Derivados, consulte la documentación de Conjuntos de Datos Derivados.
  • +
+

Resultados de la Búsqueda#

+

+
    +
  • En Vertex, una escena se considera un paquete que contiene todos los archivos, o productos, que están relacionados con una ubicación y tiempo específicos.
  • +
  • Por ejemplo, la columna de la izquierda del panel de Resultados muestra las escenas devueltas por una búsqueda. La columna de la derecha muestra el contenido de archivos de cada escena.
  • +
  • El número máximo de archivos que una búsqueda devolverá se muestra debajo del botón BUSCAR.
  • +
  • Este número se puede ajustar haciendo clic en la flecha hacia abajo.
  • +
  • También se muestra el número total de archivos que coinciden con los parámetros de búsqueda.
  • +
  • La barra de encabezado de Resultados.
  • +
  • El botón Zoom acercará a la ubicación de todas las escenas en el mapa.
  • +
  • El botón Lista agregará todas las escenas a la lista de descarga.
  • +
  • El botón A Demanda le permitirá elegir qué escenas elegibles agregar a la Lista de A Demanda para un procesamiento adicional.
  • +
  • El botón Bruto mostrará u ocultará archivos brutos. Nota: Este botón es aplicable solo para escenas de Sentinel-1.
  • +
  • El botón Exportar o Pares le permitirá exportar datos o metadatos para todas las escenas en los resultados.
  • +
  • El botón Expirado mostrará u ocultará archivos a demanda expirados. Nota: Este botón solo está disponible en el tipo de búsqueda de Productos a Demanda.
  • +
  • El botón Copiar le permitirá copiar IDs de escenas o URLs. Nota: Este botón solo está disponible en el tipo de búsqueda de Eventos.
  • +
  • Nota: No todos los botones están disponibles en todos los tipos de búsqueda.
  • +
  • La columna de Escenas (izquierda).
  • +
  • Haga clic en el icono del carrito junto al nombre de una escena para agregar todos los archivos de la escena a la lista de descarga. El carrito cambia de apariencia cuando esto se hace.
  • +
  • Haga clic en el icono de zoom junto al nombre de una escena para acercar a la ubicación de la escena en el mapa.
  • +
  • Haga clic en el botón A Demanda para agregar escenas elegibles a la Lista de A Demanda para un procesamiento adicional.
  • +
  • Para ver más información sobre una escena, haga clic en la escena en la columna de la izquierda y las columnas de Detalle de Escena y Archivos se completarán.
  • +
  • La columna Detalle de Escena (centro) proporciona una descripción más detallada de la escena, incluyendo Fecha/Hora de Inicio, Modo de Haz, Ruta, Cuadro, Dirección de Vuelo, Polarización, Órbita Absoluta y una imagen de navegación (si está disponible). No todas las escenas tendrán toda la información adicional.
      +
    • El botón Línea base abre la Herramienta Línea base de ASF, que se usa para crear pilas InSAR.
    • +
    • El botón SBAS abre la Herramienta SBAS de ASF, que es otro método para crear pilas InSAR.
    • +
    • El botón Más Como Esto crea una búsqueda basada en la ruta y el cuadro de la escena seleccionada. +
    • +
    • El botón Datos de Origen crea una búsqueda para la escena Sentinel-1 de origen basada en el ID de Grupo del producto Opera. Nota: Este botón solo está disponible para los resultados de búsqueda de Opera-S1.
    • +
    • El botón Citación abre una nueva ventana con orientación para citar trabajos publicados que utilicen datos, imágenes o herramientas accedidas a través de ASF.
    • +
    • Descargar esta Imagen descarga la imagen de navegación.
    • +
    • El icono del ojo etiquetado Abrir en Visor de Imágenes abre una ventana de visor de navegación más grande.
    • +
    • En el visor de navegación, acerque usando los botones + o -. También puede acercar y desplazar usando el ratón.
    • +
    • Haga clic o desplace a través de las miniaturas en la parte inferior para ver otras imágenes de navegación para las escenas devueltas por su búsqueda.
    • +
    • De manera predeterminada, la casilla Solo mostrar escenas con imagen de navegación está marcada. Puede desmarcar esto para ver todas las escenas devueltas por su búsqueda. Las escenas sin imagen de navegación mostrarán una miniatura que indica No hay Navegación Disponible.
    • +
    • Los metadatos de la escena se enumeran en el lado derecho de la ventana del visor de navegación.
    • +
    • Haga clic en un archivo para descargarlo inmediatamente o agregarlo a la lista de descarga.
    • +
    +
  • +
  • La columna Archivos (derecha) muestra una lista de archivos disponibles para la escena seleccionada actualmente. Puede descargar archivos inmediatamente o agregarlos a su lista de descarga haciendo clic en el icono correspondiente. También puede agregar archivos elegibles a la lista de A Demanda para un procesamiento adicional.
  • +
+

Lista On Demand#

+

+
    +
  • Al hacer clic en el icono de tres cuadros en el encabezado, etiquetado como On Demand, se mostrará una lista desplegable de opciones.
  • +
  • On Demand Queue abrirá la lista On Demand.
  • +
  • Los diferentes tipos de trabajos en su lista están separados por pestañas en la parte superior de la lista. Puede hacer clic en una pestaña para seleccionarla. La pestaña seleccionada está resaltada.
  • +
  • Algunos tipos de trabajo tienen opciones de procesamiento adicionales disponibles. Las opciones que seleccione se aplicarán a todos los archivos de ese tipo de trabajo en su lista.
      +
    • Puede pasar el cursor sobre cada opción para mostrar una herramienta con detalles sobre la opción.
    • +
    +
  • +
  • Elija su orden de clasificación deseado con los cuadros desplegables Criterios de Clasificación y Orden de Clasificación.
      +
    • Bajo Criterios de Clasificación, puede elegir ordenar los archivos por Fecha de Inicio del archivo o por Fecha Agregada a la lista.
    • +
    • Bajo Orden de Clasificación, puede elegir ordenar los archivos por Más Recientes o por Más Antiguos.
    • +
    +
  • +
  • La lista de archivos que ha agregado a su lista se muestra debajo de las opciones. La X le permite eliminar cualquier archivo que desee de la lista.
  • +
  • Borrar mostrará algunas opciones para borrar archivos de su lista. Puede elegir borrar una pestaña individual, o puede elegir Borrar Todos los Tipos de Procesamiento para borrar todos los archivos de la lista. Si elige borrar todos los archivos, se mostrará la opción Restaurar para permitirle deshacer esta acción.
  • +
  • El número de créditos restantes se muestra en la parte inferior de la lista. Cada tipo de trabajo usa una cantidad específica de créditos. El botón Enviar enumerará el número total de créditos que utilizarán sus trabajos. Si tiene demasiados trabajos en su lista, el botón Enviar estará desactivado.
  • +
  • Cuando esté satisfecho con sus selecciones, haga clic en Enviar Trabajos en la parte inferior. Esto mostrará la ventana de Revisión de Envío.
      +
    • El campo Nombre del Proyecto le permite crear un nombre para los archivos que desea enviar para procesamiento. El límite de caracteres es 20. Este campo es opcional.
    • +
    • Puede seleccionar o deseleccionar las casillas para enviar solo los tipos de trabajos que desee.
    • +
    • Seleccione Cancelar para regresar a la lista sin enviar ningún archivo para procesamiento.
    • +
    • Haga clic en Submit para enviar sus trabajos. Nota: El botón Enviar enumerará la cantidad de trabajos y la cantidad de créditos que está enviando.
    • +
    • Si hay algún error, como cobertura DEM faltante, se mostrará un mensaje de error.
    • +
    +
  • +
  • Submitted Products cambiará al tipo de búsqueda de Productos On Demand y mostrará sus productos enviados.
  • +
  • On Demand (HyP3) Docs lo llevará a la documentación de On Demand
  • +
  • Nota: Debe iniciar sesión para ver sus Submitted Products y para enviar trabajos desde la On Demand Queue.
  • +
+

Lista de Descargas#

+

+

La funcionalidad mejorada de la lista de descargas ahora está disponible en el navegador Google Chrome. Vea a continuación para más información.

+
    +
  • Al hacer clic en el icono del carrito en el encabezado, etiquetado como Descargas, se mostrarán los contenidos de su lista de descargas actual.
  • +
  • Dentro de la lista de descargas, la lista de archivos que ha seleccionado para descargar se muestra con información básica sobre cada archivo, como el tipo de archivo y el tamaño.
      +
    • Los IDs de archivo (nombres) se pueden copiar con el icono de copiar.
    • +
    • Los archivos se pueden descargar individualmente con el icono de nube. También puede hacer clic derecho para guardar o copiar la URL de descarga.
    • +
    • Los elementos se pueden eliminar de la lista con la X.
    • +
    +
  • +
  • Borrar limpiará todos los archivos de la lista. La opción Restaurar se mostrará para permitirle deshacer esta acción.
  • +
  • Copiar IDs de Archivos copiará los nombres de archivo de todos los archivos en la lista para su uso en otros lugares. Por ejemplo, esta lista podría pegarse en la ventana de Búsqueda de Lista.
  • +
  • Copiar URLs copiará las URLs de descarga de todos los archivos en la lista.
  • +
  • Descarga de Datos se utiliza para descargar múltiples productos, con la opción Descargar Script de Python (.py) o la opción de archivo Metalink (metalink).
  • +
  • Descarga de Metadatos se utiliza para exportar el contenido de la lista de descargas a un archivo CSV, KML o GeoJSON. Los archivos KML y GeoJSON proporcionados por esta función son compatibles con la función de Importación de Búsqueda Geográfica.
  • +
+ +

La funcionalidad mejorada de la lista de descargas está disponible en el navegador Google Chrome. Tenga en cuenta que esta funcionalidad mejorada no es compatible cuando se usa el modo incógnito.

+
    +
  • Haga clic en el icono del carrito en el encabezado, etiquetado como Descargas para abrir su lista de descargas.
  • +
  • Junto a cada archivo, puede hacer clic en el icono de nube para comenzar la descarga.
      +
    • Al comenzar la descarga, un indicador de progreso muestra el porcentaje descargado. Una vez que la descarga se haya completado, el icono aparecerá como una marca de verificación para indicar que el archivo ha sido descargado.
    • +
    • Mientras el archivo se está descargando, puede hacer clic en el indicador de progreso para detener la descarga.
    • +
    +
  • +
  • Bajo Descarga de Datos, puede seleccionar Descargar Todo. Esto descargará 3 archivos a la vez hasta que todos los productos en su carrito se hayan descargado. Los mismos indicadores de progreso y marcas de verificación se mostrarán para informarle el estado de cada descarga en su lista.
      +
    • Cuando haga clic en Descargar Todo, aparecerá un cuadro de diálogo:
    • +
    • Navegue a la carpeta donde desea guardar los archivos y haga clic en Seleccionar.
    • +
    • Haga clic en Ver Archivos para permitir que la descarga continúe.
    • +
    • Haga clic en Guardar Cambios para guardar sus preferencias de carpeta de descarga. Esto persistirá mientras la ventana del navegador Vertex permanezca abierta.
    • +
    +
  • +
  • Si Borra los productos en su lista, los indicadores de progreso y finalización de la descarga se restablecerán. Puede agregar los productos a su lista nuevamente si lo desea.
  • +
  • Nota: Debe iniciar sesión para descargar archivos. Si no ha iniciado sesión, cuando haga clic para comenzar una descarga, será redirigido primero a la página de inicio de sesión.
  • +
+

Otras Opciones de Vertex#

+
    +
  • En la esquina superior izquierda del mapa, hay botones que le permiten cambiar su vista del mapa, zoom y capas. Nota: Los controles del mapa disponibles varían según el tipo de búsqueda. +
  • +
  • De manera predeterminada, el mapa está en proyección ecuatorial. Puede hacer clic en Vista de Mapa y seleccionar Vista de Mapa Ártico o Vista de Mapa Antártico para cambiar su proyección de mapa. Haga clic en Vista de Mapa Ecuatorial para volver a la proyección ecuatorial.
  • +
  • Puede hacer clic en los iconos de Acercar o Alejar para ajustar su zoom.
  • +
  • La capa de mapa predeterminada es satelital. Puede hacer clic en el botón Capas y seleccionar Vista Satelital o Vista de Calle para cambiar su capa de mapa.
      +
    • Puede hacer clic en Mapa de Vista General para agregar un mapa de vista general en la esquina superior derecha del mapa. Haga clic nuevamente para apagar el mapa de vista general.
    • +
    • Puede hacer clic en Capa de Coherencia para seleccionar una capa de coherencia estacional. Haga clic en la burbuja junto a la estación que desea activar. Haga clic nuevamente en la casilla de verificación de la Capa de Coherencia para desactivar la capa.
    • +
    • Puede hacer clic en Líneas de Cuadrícula para agregar una superposición de retícula al mapa. Haga clic nuevamente para desactivar la superposición. Nota: Esto actualmente solo está disponible en la vista de mapa ecuatorial.
    • +
    +
  • +
  • Puede hacer clic en Opacidad y ajustar el control deslizante según lo desee para cambiar la opacidad de las imágenes de navegación que se muestran en el mapa. Si la Capa de Coherencia está activada, también puede ajustar la opacidad de esa capa.
  • +
  • Haga clic en la flecha hacia abajo en el Buscar
  • +
  • Borrar Búsqueda borrará todos los parámetros de búsqueda que se hayan establecido, excepto el Tipo de Búsqueda y el Conjunto de Datos.
  • +
  • Búsquedas Guardadas abre un submenú. Nota: Debe iniciar sesión en Vertex para que esta opción esté disponible. +
      +
    • Guardar Búsqueda le permite nombrar y guardar su búsqueda actual.
    • +
    • Ver Búsquedas... abre una lista de búsquedas que ha nombrado y guardado. Haga clic en el icono de la lupa para cargar la configuración de búsqueda.
    • +
    • Historial de Búsquedas... abre una lista de sus últimas 10 búsquedas que no fueron nombradas ni guardadas. Haga clic en el icono de la lupa para cargar la configuración de búsqueda.
    • +
    +
  • +
  • Filtros Guardados abre un submenú. Nota: Debe iniciar sesión en Vertex para que esta opción esté disponible.
      +
    • Guardar Filtros le permite guardar su conjunto de filtros actual.
    • +
    • Ver Filtros... le permite ver sus conjuntos de filtros guardados. Haga clic en Aplicar Filtros para aplicarlos a su búsqueda actual.
    • +
    +
  • +
  • Compartir Búsqueda abre un submenú.
      +
    • Copiar Enlace de Búsqueda copiará todos los parámetros de búsqueda que se hayan establecido en la búsqueda actual como una URL. Luego, la URL se puede pegar en la barra de búsqueda del navegador para recrear exactamente la búsqueda o pegarse en un documento y guardarse para recrear la búsqueda más tarde.
    • +
    • Compartir por Correo Electrónico abrirá un nuevo correo electrónico con la URL de la búsqueda para enviar a otros.
    • +
    +
  • +
  • Ayuda y Tutoriales proporciona demostraciones ilustradas y en video sobre una variedad de temas.
  • +
  • Exportar abre un submenú.
      +
    • Exportar Python proporcionará un fragmento de código Python para recrear la búsqueda actual utilizando el paquete de búsqueda en Python asf_search. También proporciona un enlace a la documentación de asf_search.
    • +
    • Exportar API proporcionará la URL de la API para recrear la búsqueda actual utilizando la SearchAPI. También proporciona un enlace a la documentación de SearchAPI.
    • +
    +
  • +
  • Haga clic en Ayuda para obtener opciones de ayuda adicionales.
  • +
  • Ver Nuestros Tutoriales proporciona demostraciones ilustradas y en video sobre cómo usar Vertex.
  • +
  • Leer Nuestra Guía del Usuario abre la documentación de Vertex en una nueva pestaña.
  • +
  • Leer Nuestra Guía de On Demand abre la documentación de On Demand en una nueva pestaña.
  • +
  • Encontrar Datos SAR Usando la API de ASF abre la documentación de SearchAPI en una nueva pestaña.
  • +
  • Aprender Más Sobre ASF y SAR abre el sitio web de ASF en una nueva pestaña.
  • +
  • Estadísticas y Repositorio de GitHub proporciona enlaces a nuestro repositorio de Vertex en GitHub.
  • +
  • Haga clic en el icono de Idioma para seleccionar su idioma predeterminado.
  • +
  • Haga clic en el icono de Iniciar sesión una vez que haya iniciado sesión para mostrar las opciones de usuario.
  • +
  • Búsquedas Guardadas abre una lista de búsquedas que ha nombrado y guardado. Haga clic en el icono de la lupa para cargar la configuración de búsqueda.
  • +
  • Historial de Búsquedas abre una lista de sus últimas 10 búsquedas que no fueron nombradas ni guardadas. Haga clic en el icono de la lupa para cargar la configuración de búsqueda.
  • +
  • Filtros Guardados abre una lista de filtros que ha guardado. Haga clic en Aplicar Filtros para aplicar el conjunto de filtros seleccionado a su búsqueda.
  • +
  • Preferencias abre una ventana que le permite establecer preferencias de búsqueda para idioma, tema, conjunto de datos, resultados máximos, capa de mapa, preajustes de filtros predeterminados y preajustes de On Demand. Estas preferencias se guardarán y aplicarán a futuras búsquedas.
  • +
  • Nota: Búsquedas Guardadas, Filtros Guardados y Historial de Búsquedas están disponibles tanto a través del menú de inicio de sesión como del menú desplegable del botón de búsqueda.
  • +
  • Haga clic en el campo Buscar en todo ASF en la barra de encabezado gris para realizar una búsqueda. Las entradas en este campo buscarán en todos los sitios web de ASF.
  • +
  • También puede hacer clic en el icono de micrófono si prefiere usar la búsqueda por voz.
  • +
  • A medida que escribe o habla, los resultados de su búsqueda se mostrarán en una lista debajo del campo. Hacer clic en un resultado de la lista abrirá una nueva pestaña del navegador.
  • +
  • Puede hacer clic en el icono de lupa para expandir los resultados de búsqueda. Esto se abrirá en la misma ventana del navegador. Para cerrar y regresar a Vertex, haga clic en la X cerca de la esquina superior derecha de su pantalla.
  • +
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/es/vertex/sbas/index.html b/es/vertex/sbas/index.html new file mode 100644 index 0000000..bb8494c --- /dev/null +++ b/es/vertex/sbas/index.html @@ -0,0 +1,1619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + SBAS - ASF SAR Manual de Búsqueda de Datos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Herramienta de Búsqueda SBAS#

+

¿Qué es SBAS?#

+

SBAS es un acrónimo de subconjuntos de líneas de base cortas. Se trata de una técnica utilizada en interferometría. La herramienta SBAS de Vertex proporciona datos de línea de base perpendiculares y temporales, así como pares de escenas, para una escena de referencia elegida.

+

¿Cuáles son algunos usos de SBAS?#

+

SBAS se utiliza ampliamente en la comunidad de las geociencias. Funciona mejor en entornos naturales a gran escala y se puede utilizar para analizar cambios graduales a lo largo del tiempo. SBAS requiere la entrada de una serie de interferogramas y el resultado final es una serie temporal que muestra el movimiento.

+

Una ventaja de SBAS es que no estás restringido a un solo interferograma. Puede observar cambios graduales a lo largo del tiempo. También puede ser útil para conjuntos de datos más antiguos que a veces tienen adquisiciones irregulares. El filtrado temporal y espacial puede ayudar a aumentar la precisión en la medición de deformaciones.

+

Debe elegir qué interferogramas utilizar, lo que a veces puede requerir algo de experimentación. La herramienta SBAS de Vertex simplifica esto al proporcionar una buena visualización y facilitar la determinación rápida de qué escenas usar.

+

Existen otros enfoques preferidos para entornos urbanos o necesidades de mayor resolución. Sin embargo, independientemente de tus necesidades de análisis, la herramienta SBAS es una herramienta de vista general útil y también se puede utilizar como un gráfico de línea de base 2-D. Proporciona una visualización completa pero rápida de las escenas.

+

Para obtener más información sobre la línea de base, incluidas descripciones de múltiples enfoques, puede consultar aquí. También puede encontrar un estudio de caso de comparación entre PS y SBAS aquí.

+

Cómo utilizar la Herramienta SBAS de Vertex#

+

Visita Vertex de ASF para comenzar a usar la herramienta SBAS. +

+

Comenzando su Búsqueda SBAS#

+
    +
  • +

    Si no tiene una escena de referencia específica elegida, puede buscar escenas utilizando la búsqueda geográfica o por lista. La columna central tendrá un botón en la metainformación titulado Herramienta SBAS para las escenas que sean elegibles. Puede hacer clic en este botón para dirigirte a una búsqueda SBAS. La búsqueda SBAS utilizará la escena elegida como referencia.

    +
  • +
  • +

    Si tiene una escena de referencia específica elegida, puede seleccionar SBAS en la lista desplegable Tipo de Búsqueda. Puede ingresar su escena de referencia y hacer clic en Buscar.

    +
  • +
+

Interactuando con los Resultados de la Búsqueda SBAS#

+

Mientras esté en el tipo de búsqueda SBAS, notarás muchos controles familiares en el panel de resultados. Los pares se muestran en la columna izquierda. La columna central lista la metainformación de los dos extremos del par seleccionado. El Gráfico SBAS se muestra en la columna derecha.

+

Controles del Panel de Resultados

+
    +
  • En la parte superior izquierda del panel de resultados, verá el número de pares listados.
  • +
  • Ampliar permitirá Ampliar los resultados, aumentando la área del mapa de la Tierra donde se encuentran las escenas.
  • +
  • Lista permitirá Agregar todo a Descargas, lo que te permite agregar todas las escenas a la lista de descargas.
  • +
  • On Demand te permitirá Agregar todo a la lista On Demand para realizar un procesamiento personalizado en las escenas. También puede optar por Crear Suscripción.
      +
    • Puede elegir entre los tipos de trabajo disponibles para sus escenas, según sus necesidades. El procesamiento RTC se realiza en las escenas individuales de su conjunto de resultados. El procesamiento InSAR y autoRIFT se realiza en los pares de su conjunto de resultados.
    • +
    • Nota: Actualmente, solo las escenas con modo de haz IW son elegibles para el procesamiento On Demand.
    • +
    +
  • +
  • Pares te permitirá Descargar el par CSV, que lista las escenas en cada par y la URL de descarga para cada una. También incluye los valores de la línea de base.
  • +
  • En la columna de la izquierda, resalte el par deseado y haga clic en el icono On Demand para Agregar par a la lista On Demand. Puede elegir el tipo de trabajo deseado para cada par.
  • +
+

Controles del Gráfico

+
    +
  • Los puntos en el gráfico representan escenas individuales. Al pasar el cursor sobre ellos, se mostrará su información temporal y perpendicular. Las líneas representan los pares.
  • +
  • Puede utilizar el ratón para navegar por el gráfico. Hay botones de Ampliar y Reducir ubicados encima del gráfico. El botón Ajustar al Tamaño ajustará todos los pares en el gráfico visible.
  • +
  • Puede hacer clic en cualquier línea de par en el gráfico. Cuando lo hagas, el par seleccionado se resaltará en rojo y se mostrará la metainformación de ese par en la columna central.
  • +
  • Puede ajustar la línea de base temporal y perpendicular utilizando los controles deslizantes en el gráfico.
  • +
  • También puede crear su propio par si lo desea:
      +
    1. Bajo Par Personalizado, haga clic en el símbolo de más para Comenzar a agregar un par personalizado.
    2. +
    3. Haga clic en el punto en el gráfico que representa la primera escena.
    4. +
    5. Haga clic en el punto en el gráfico que representa la segunda escena.
    6. +
    7. Se creará el nuevo par y se añadirá el detalle del par en la parte inferior de la lista de resultados. Los pares añadidos manualmente se mostrarán con una línea punteada en el gráfico.
    8. +
    9. Nota: También puede agregar pares personalizados a la lista On Demand.
    10. +
    +
  • +
  • Si desea dejar de agregar un par después de haber comenzado, puede hacer clic en el símbolo cuadrado para Dejar de agregar un par personalizado. Ten en cuenta que solo se pueden eliminar los pares añadidos manualmente.
  • +
+

Mensaje de Advertencia sobre Detección de Brechas#

+

Si se detectan brechas en tus pares SBAS, se mostrará un mensaje de advertencia. Se recomienda evitar las redes de pares InSAR desconectadas. Las redes de pares desconectadas dificultan la creación de estimaciones imparciales de las velocidades InSAR en un análisis de series temporales.

+

Si desea eliminar las brechas, puede modificar tus filtros de búsqueda, como aumentar la línea de base temporal hasta que todas las escenas estén conectadas. También puede agregar pares manuales para las conexiones faltantes. Una vez que todas las escenas tengan al menos una conexión, el mensaje de advertencia desaparecerá.

+

Criterios de SBAS#

+
    +
  • Haga clic en Criterios de SBAS... para obtener opciones de filtrado adicionales.
      +
    • Puede ingresar una fecha de Inicio o Fin, o seleccionar fechas en el calendario.
    • +
    • Búsqueda Estacional permite limitar los resultados a ciertos períodos anuales dentro de un rango general de fechas. Haga clic en el interruptor de Búsqueda Estacional y aparecerán opciones adicionales, lo que te permitirá ajustar los controles deslizantes para especificar un rango estacional (Día de Inicio de la Temporada/Día de Finalización de la Temporada).
    • +
    • Superposición Latitudinal te permite establecer el umbral de superposición para los pares. Filtrar los pares que no se superponen puede reducir errores en el procesamiento InSAR On Demand.
        +
      • Sin Umbral de Superposición es el valor predeterminado. Se devuelven todos los resultados de pares, incluidos los que no se superponen.
      • +
      • Cualquier Umbral de Superposición asegurará que todos los pares tengan cierta superposición. Los pares sin superposición se filtrarán de los resultados.
      • +
      • Umbral de Superposición del 50% garantiza que todos los pares tengan aproximadamente un 50% de superposición. Los pares con menos superposición se filtrarán de los resultados.
      • +
      +
    • +
    +
  • +
+

Siguientes Pasos#

+

El siguiente paso es crear interferogramas. Puede hacerlo a través del procesamiento On Demand en Vertex. Primero, debe agregar algunos o todos los pares a la lista On Demand como trabajos InSAR. En la lista , hay opciones limitadas disponibles para personalizar su procesamiento InSAR. También puede especificar un nombre de proyecto. Envía la lista cuando hayas seleccionado todas las opciones deseadas. Cuando los interferogramas estén completos, Podrá verlos y descargarlos utilizando el tipo de búsqueda de Productos On Demand en Vertex.

+

Para áreas con hielo glaciar, autoRIFT es otra opción de procesamiento. Similar a InSAR, debe agregar algunos o todos los pares a la lista On Demand como trabajos autoRIFT. No hay opciones de personalización adicionales disponibles para el procesamiento autoRIFT, pero aún puede especificar un nombre de proyecto. Cuando se complete el procesamiento autoRIFT, Podrá ver y descargar los productos utilizando el tipo de búsqueda de Productos On Demand en Vertex.

+

Puede encontrar más detalles en la Guía del Usuario de Vertex. También hay documentación de ayuda, incluidos videos, disponible en Vertex aquí.

+

Para obtener más información, también puede consultar la documentación de On Demand.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/google49421f25268ef0ea.html b/google49421f25268ef0ea.html new file mode 100644 index 0000000..1773151 --- /dev/null +++ b/google49421f25268ef0ea.html @@ -0,0 +1 @@ +google-site-verification: google49421f25268ef0ea.html \ No newline at end of file diff --git a/google753725a6795ccf42.html b/google753725a6795ccf42.html new file mode 100644 index 0000000..61d0bdc --- /dev/null +++ b/google753725a6795ccf42.html @@ -0,0 +1 @@ +google-site-verification: google753725a6795ccf42.html \ No newline at end of file diff --git a/images/absolute_burst_id_diagram.png b/images/absolute_burst_id_diagram.png new file mode 100644 index 0000000..a621f54 Binary files /dev/null and b/images/absolute_burst_id_diagram.png differ diff --git a/images/full_burst_id_diagram.png b/images/full_burst_id_diagram.png new file mode 100644 index 0000000..d13a21b Binary files /dev/null and b/images/full_burst_id_diagram.png differ diff --git a/images/relative_burst_id_diagram.png b/images/relative_burst_id_diagram.png new file mode 100644 index 0000000..7202ef6 Binary files /dev/null and b/images/relative_burst_id_diagram.png differ diff --git a/images/single_burst_diagram.png b/images/single_burst_diagram.png new file mode 100644 index 0000000..f3446dd Binary files /dev/null and b/images/single_burst_diagram.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..cb44bb7 --- /dev/null +++ b/index.html @@ -0,0 +1,1475 @@ + + + + + + + + + + + + + + + + + + + + + + + ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Welcome to ASF SAR Data Search#

+ +

ASF Data Search is an easy to use search tool for finding SAR data and freely processing higher level SAR products such as InSAR and AutoRIFT products with ASF's HyP3 service. See our user guide on getting started.

+

For an overview of all of ASF services visit asf.alaska.edu.

+
+

Search Tool Documentation

+ +
+
+
+
+

Vertex

+

A graphical search interface for finding SAR data.

+ +
+
+
+
+
+
+

HyP3

+

Process SAR data to create refined products.

+ +
+
+
+
+ +
+
+
+
+

asf_search

+

A Python package for performing searches of the ASF catalog.

+ +
+
+
+
+
+
+

ASF API

+

A command-line interface for finding SAR data.

+ +
+
+
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/index.key b/index.key new file mode 100644 index 0000000..3fe3fb3 --- /dev/null +++ b/index.key @@ -0,0 +1 @@ +{{ INDEX_1 }} \ No newline at end of file diff --git a/javascripts/consent.js b/javascripts/consent.js new file mode 100644 index 0000000..9417549 --- /dev/null +++ b/javascripts/consent.js @@ -0,0 +1,90 @@ +// This entire file will be remarked out. It is only here for reference. +// This is the code that is used to set the cookie for the cookie consent banner, using the idea +// that we will maintain a cross-subdomain cookie for the user's consent status. +// For now, this idea is shelved because the effort to change Vertex cookie logic and the effort +// needed to change the MkDocs Material templates use of a non-standard cookie that really isn't a "cookie". +// +// https://dev.to/text/setting-cookies-to-subdomains-in-javascript-1md9 +// let Cookie = +// { +// set: function(name, value, days) +// { +// let domain, domainParts, date, expires, host; +// +// if (days) +// { +// date = new Date(); +// date.setTime(date.getTime()+(days*24*60*60*1000)); +// expires = "; expires="+date.toGMTString(); +// } +// else +// { +// expires = ""; +// } +// +// host = location.host; +// if (host.split('.').length === 1) +// { +// // no "." in a domain - it's localhost or something similar +// document.cookie = name+"="+value+expires+"; path=/"; +// } +// else +// { +// // Remember the cookie on all subdomains. +// // +// // Start with trying to set cookie to the top domain. +// // (example: if user is on foo.com, try to set +// // cookie to domain ".com") +// // +// // If the cookie will not be set, it means ".com" +// // is a top level domain and we need to +// // set the cookie to ".foo.com" +// domainParts = host.split('.'); +// domainParts.shift(); +// domain = '.'+domainParts.join('.'); +// +// document.cookie = name+"="+value+expires+"; path=/; domain="+domain; +// +// // check if cookie was successfuly set to the given domain +// // (otherwise it was a Top-Level Domain) +// if (Cookie.get(name) == null || Cookie.get(name) != value) +// { +// // append "." to current domain +// domain = '.'+host; +// document.cookie = name+"="+value+expires+"; path=/; domain="+domain; +// } +// } +// }, +// +// get: function(name) +// { +// const nameEQ = name + "="; +// const ca = document.cookie.split(';'); +// for (let i=0; i < ca.length; i++) +// { +// let c = ca[i]; +// while (c.charAt(0)==' ') +// { +// c = c.substring(1,c.length); +// } +// +// if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); +// } +// return null; +// }, +// +// erase: function(name) +// { +// Cookie.set(name, '', -1); +// } +// }; +// +// let stats = Cookie.get("cookieconsent_status") +// console.log("Cookie consent status: " + stats); +// +// if (stats === "dismiss") { +// console.log("User dismissed the notification"); +// } else { +// Cookie.set("cookieconsent_status", "dismiss", 1); +// console.log("set the cookieconsent_status to dismiss"); +// } diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..9aebb8d --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,367 @@ + + + + None./ + 2024-11-05 + daily + + + + + Noneapi/basics/ + 2024-11-05 + daily + + + + + Noneapi/changelog/ + 2024-11-05 + daily + + + + + Noneapi/cookbook/ + 2024-11-05 + daily + + + + + Noneapi/keywords/ + 2024-11-05 + daily + + + + + Noneapi/tools/ + 2024-11-05 + daily + + + + + Noneapi/troubleshooting/ + 2024-11-05 + daily + + + + + Noneasf_search/ASFProduct/ + 2024-11-05 + daily + + + + + Noneasf_search/ASFSearchOptions/ + 2024-11-05 + daily + + + + + Noneasf_search/ASFSearchResults/ + 2024-11-05 + daily + + + + + Noneasf_search/ASFSession/ + 2024-11-05 + daily + + + + + Noneasf_search/BestPractices/ + 2024-11-05 + daily + + + + + Noneasf_search/basics/ + 2024-11-05 + daily + + + + + Noneasf_search/downloading/ + 2024-11-05 + daily + + + + + Noneasf_search/exceptions/ + 2024-11-05 + daily + + + + + Noneasf_search/searching/ + 2024-11-05 + daily + + + + + Nonedatasets/displacement/ + 2024-11-05 + daily + + + + + Nonedatasets/events_about/ + 2024-11-05 + daily + + + + + Nonedatasets/palsar/ + 2024-11-05 + daily + + + + + Nonedatasets/using_ASF_data/ + 2024-11-05 + daily + + + + + Nonevertex/baseline/ + 2024-11-05 + daily + + + + + Nonevertex/changelog/ + 2024-11-05 + daily + + + + + Nonevertex/derived_datasets/ + 2024-11-05 + daily + + + + + Nonevertex/events/ + 2024-11-05 + daily + + + + + Nonevertex/manual/ + 2024-11-05 + daily + + + + + Nonevertex/sbas/ + 2024-11-05 + daily + + + + + Nonees/ + 2024-11-05 + daily + + + + + Nonees/api/basics/ + 2024-11-05 + daily + + + + + Nonees/api/changelog/ + 2024-11-05 + daily + + + + + Nonees/api/cookbook/ + 2024-11-05 + daily + + + + + Nonees/api/keywords/ + 2024-11-05 + daily + + + + + Nonees/api/tools/ + 2024-11-05 + daily + + + + + Nonees/api/troubleshooting/ + 2024-11-05 + daily + + + + + Nonees/asf_search/ASFProduct/ + 2024-11-05 + daily + + + + + Nonees/asf_search/ASFSearchOptions/ + 2024-11-05 + daily + + + + + Nonees/asf_search/ASFSearchResults/ + 2024-11-05 + daily + + + + + Nonees/asf_search/ASFSession/ + 2024-11-05 + daily + + + + + Nonees/asf_search/BestPractices/ + 2024-11-05 + daily + + + + + Nonees/asf_search/basics/ + 2024-11-05 + daily + + + + + Nonees/asf_search/downloading/ + 2024-11-05 + daily + + + + + Nonees/asf_search/exceptions/ + 2024-11-05 + daily + + + + + Nonees/asf_search/searching/ + 2024-11-05 + daily + + + + + Nonees/datasets/displacement/ + 2024-11-05 + daily + + + + + Nonees/datasets/events_about/ + 2024-11-05 + daily + + + + + Nonees/datasets/palsar/ + 2024-11-05 + daily + + + + + Nonees/datasets/using_ASF_data/ + 2024-11-05 + daily + + + + + Nonees/vertex/baseline/ + 2024-11-05 + daily + + + + + Nonees/vertex/changelog/ + 2024-11-05 + daily + + + + + Nonees/vertex/derived_datasets/ + 2024-11-05 + daily + + + + + Nonees/vertex/events/ + 2024-11-05 + daily + + + + + Nonees/vertex/manual/ + 2024-11-05 + daily + + + + + Nonees/vertex/sbas/ + 2024-11-05 + daily + + + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000..88f67ea Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/vertex/baseline.key b/vertex/baseline.key new file mode 100644 index 0000000..a227b53 --- /dev/null +++ b/vertex/baseline.key @@ -0,0 +1 @@ +{{ BASELINE_1 }} \ No newline at end of file diff --git a/vertex/baseline/index.html b/vertex/baseline/index.html new file mode 100644 index 0000000..1908343 --- /dev/null +++ b/vertex/baseline/index.html @@ -0,0 +1,1563 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Baseline - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Baseline Search Type#

+

What is Baseline?#

+

Baseline uses information from two synthetic aperture radar (SAR) images of the same target area acquired at different times (temporal baseline) and from slightly different satellite orbit positions (perpendicular baseline). The Vertex baseline tool helps you identify and select scene pairs that are appropriate for Interferometric SAR (InSAR) processing. It provides visualization of perpendicular and temporal baseline data, and allows you to easily change the reference scene used in any stack.

+

How to use Vertex Baseline Tool#

+

Visit ASF's Vertex to begin using the Baseline tool. +

+ +
    +
  • +

    If you do not have a particular reference scene chosen, you can search for scenes using the geographic or list search. The center column will have a button under the metadata titled Baseline Tool for any scenes that are eligible. You may click this button to be directed to a Baseline search. The Baseline search will use the chosen scene as the reference scene.

    +
  • +
  • +

    If you do have a particular reference scene chosen, you can select Baseline from the Search Type dropdown list. You may enter your reference scene and hit Search.

    +
  • +
+

Interacting with Baseline Search Results#

+

While in Baseline Search type, you will notice many familiar controls in the results panel. The scenes are shown in the left column. The perpendicular and temporal baselines are listed next to each scene. The center column lists the metadata for the selected scene, and includes the Baseline button, which allows you to set any scene in the stack as the reference scene. The Baseline Chart is shown in the right column.

+

Result Panel Controls

+
    +
  • At the top left of the results panel, you will see the number of scenes listed.
  • +
  • Zoom will Zoom to results magnifying the map area of the Earth where the scenes are located.
  • +
  • Queue will Add all results to Downloads allowing you to add all scenes to the download queue.
  • +
  • On Demand will allow you to Add all results to On Demand queue to do custom processing on the scenes. To learn more click here.
  • +
  • Export will allow you to Download data/metadata for all scenes in the stack.
  • +
  • In the left column, Queue will Add scene files to downloads for the selected scene only.
  • +
  • Under the metadata in the center column, Baseline will allow you to set any scene in the stack as the reference scene. When you select this, both the chart and the baseline values will be updated automatically.
  • +
+

Chart Controls

+
    +
  • The dots on the chart represent individual scenes. Hovering over them will list their temporal and perpendicular values. You may also click on any point to select that scene. The metadata in the center column will be updated.
  • +
  • Located above the chart, there are labels and corresponding colors. These indicate how the reference scene, selected scene, and any scenes in your download queue are displayed on the chart. Some datasets include a shaded area which indicates the critical baseline.
  • +
  • You may zoom and pan the chart.
  • +
+

Baseline Criteria#

+
    +
  • You may click Baseline Criteria... above the chart for additional options.
      +
    • You can adjust the sliders to change the perpendicular and temporal values that you wish to be included in your results.
    • +
    • Seasonal Search allows constraining the results to certain annual periods within an overall range of dates. Click the Seasonal Search toggle and additional options will appear, allowing you to adjust the sliders to specify a seasonal range (Season Start Day/Season End Day).
    • +
    • You can enter a start and end date.
    • +
    • Changing any criteria will automatically update the list of scenes and the chart.
    • +
    +
  • +
+

Next Steps#

+

Once you are satisfied with your result set, you can use the download queue to manage and download baseline results. More information about the download queue can be found in the Vertex Getting Started User Guide.

+

If you wish to create interferograms, custom processing is now available through Vertex. Details are available in the On Demand Queue section of the Vertex Getting Started User Guide. You can find more information about creating interferograms with ASF's custom processing through the HyP3 documentation.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/vertex/changelog.key b/vertex/changelog.key new file mode 100644 index 0000000..0cffc89 --- /dev/null +++ b/vertex/changelog.key @@ -0,0 +1 @@ +{{ CHANGELOG_1 }} \ No newline at end of file diff --git a/vertex/changelog/index.html b/vertex/changelog/index.html new file mode 100644 index 0000000..b42a55b --- /dev/null +++ b/vertex/changelog/index.html @@ -0,0 +1,1474 @@ + + + + + + + + + + + + + + + + + + + + + + + + + What's New - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + +

What's New#

+

Vertex is Now Multilingual!#

+

Vertex now supports English and Spanish. If your browser language is set to Spanish, Vertex will default to Spanish. You can also select your preferred language from the top menu. More information can be found here.

+

Area of Interest: Search for a Location#

+

You can now search for a location name as your area of interest. The Search for a Location field can be found by opening the Area of Interest window. More information can be found here.

+

New On Demand Option#

+

Sentinel-1 RTCs may now be processed at 10-meter pixel spacing. More information can be found here. More about the On Demand queue can be found here.

+

Enhanced Downloads for Google Chrome#

+

Enhanced download queue functionality is available on Google Chrome browser. Included are download progress indicators, and the option to download all files in the queue. Download all will download 3 files concurrently until all files in the queue have been downloaded. More information can be found here.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/vertex/derived_datasets.key b/vertex/derived_datasets.key new file mode 100644 index 0000000..303bfeb --- /dev/null +++ b/vertex/derived_datasets.key @@ -0,0 +1 @@ +{{ DERIVED_DATASETS_1 }} \ No newline at end of file diff --git a/vertex/derived_datasets/index.html b/vertex/derived_datasets/index.html new file mode 100644 index 0000000..2840402 --- /dev/null +++ b/vertex/derived_datasets/index.html @@ -0,0 +1,1550 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Derived Datasets - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Derived Datasets Search Type#

+

What are Derived Datasets?#

+

Derived datasets are higher-level datasets created using SAR data. The datasets listed below are ASF's collection.

+

Global Seasonal Sentinel-1 Interferometric Coherence & Backscatter Dataset#

+

This dataset is the first-of-its-kind spatial representation of multi-seasonal, global SAR repeat-pass interferometric coherence and backscatter signatures. Global coverage comprises all land masses and ice sheets from 82 degrees northern to 78 degrees southern latitude. The dataset is derived from high-resolution multi-temporal repeat-pass interferometric processing of about 205,000 Sentinel-1 Single-Look-Complex (SLC) data acquired in Interferometric Wide-Swath mode (Sentinel-1 IW mode) from 1-Dec-2019 to 30-Nov-2020. Further information can be found here.

+

Global Ice Sheet Mapping Observatory (GISMO)#

+

The Global Ice-Sheet Mapping Observatory (GISMO) spaceborne radar system is part of the NASA Instrument Incubator Project (IIP). GISMO has a specific focus in measuring the surface topography of ice sheets, ice-sheet thickness, and in uncovering physical properties of the glacier bed using SAR. It utilized VHF and P-band interferometric radars and tested different methods of clutter rejection. GISMO achieved mapping the physical properties of a glacier bed through up to 5 km of ice. The GISMO project documented flight lines over the Greenland ice sheet in 2006, 2007, and 2008. Further information can be found here.

+

Glacier Speed#

+

This dataset was produced by Evan Burgess and colleagues at the University of Utah and the University of Alaska Fairbanks using ALOS PALSAR data. It reveals complex patterns of glacier flow throughout Alaska. The speed data are available for download in formats designed both for scientists and educators. Surface velocities are available for 47,880 km^2 of glacier ice, which includes almost all of the state’s major glaciers. Detailed information on its production is available in Burgess et al., Nature Communications, 2013. Further information can be found here.

+

International Polar Year#

+

International Polar Year (IPY) is a collaborative research event focused on the Arctic and Antarctic. IPY 2007-2009 focused on collaborative research and extensively explored the complex relationships between the Arctic and Antarctic. Over 60 countries and thousands of researchers participated, investigating more than 200 projects. Topics include Arctic and Antarctic relationships with geophysical elements, oceans and sea ice, Earth’s atmosphere, space, and human relations. ASF hosts an archive of the IPY project titled the Global Inter-agency IPY Polar Snapshot Year (GIIPSY). GIIPSY’s objective was to obtain high-definition satellite snapshots of the polar regions during 2007-2008. Further information can be found here.

+

Radarsat-1 Antarctic Mapping Project (RAMP)#

+

The RADARSAT-1 Antarctic Mapping Project (RAMP) is composed of two main missions, the first Antarctic Mapping Mission (AMM-1) and the Modified Antarctic Mapping Mission (MAMM). AMM-1 started on September 9, 1997 and was completed on October 20, 1997. Its goals were to acquire a complete map of Antarctica and better understand the relationships between the southernmost continent’s environmental elements. MAMM started on September 3, 2000 and was completed on November 17, 2000. It planned to remap Antarctica and measure ice velocity data using interferometric analysis and data from AMM-1. Further information can be found here.

+

Sea Ice MEaSUREs#

+

Sea-ice imagery and data products are supported under NASA’s Making Earth System data records for Use in Research Environments (MEaSUREs) program. Arctic and Southern Ocean imagery, data, and data products are available at no cost to approved users from the ASF DAAC. These include over 11 years of RADARSAT-1 three-day radar snapshots of Arctic and Southern Ocean sea ice, and original SAR images. RADARSAT-1 data have been processed to construct a near decadal record of small-scale ice motion of the Arctic and Southern Oceans, a record of ice motion of the northern Bering Sea, and monthly high-resolution image mosaics of the Arctic Ocean. Further information can be found here.

+

Wetlands MEaSUREs#

+

The inundated wetlands Earth System Data Record (ESDR) consists of two primary components. First, fine-resolution maps of wetland extent, vegetation type, and seasonal inundation dynamics, derived from SAR for regional and continental-scale areas covering crucial wetlands systems. Second, global coarse-resolution time series mappings of inundated area fraction at ~25 km resolution derived from multiple satellite remote sensing observations including passive and active microwave sensors and optical data sets optimized for inundation detection. These datasets are provided on a bi-monthly basis for 1992-1999 and daily for 2000 onward. Annual summary products and a daily near real time (NRT) dataset with 2-3 day latency are also provided. Further information can be found here.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/vertex/events.key b/vertex/events.key new file mode 100644 index 0000000..77738ec --- /dev/null +++ b/vertex/events.key @@ -0,0 +1 @@ +{{ EVENTS_SEARCH_1 }} \ No newline at end of file diff --git a/vertex/events/index.html b/vertex/events/index.html new file mode 100644 index 0000000..8917ddd --- /dev/null +++ b/vertex/events/index.html @@ -0,0 +1,1592 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Event - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Event Search Type#

+ +

Event search harnesses the capabilities of SAR proccessing to monitor natural disasters. Currently supported hazards are volcanic eruptions and earthquakes. Generated products include fully terrain corrected image time series, as well as interferometric SAR data over areas affected by natural disasters. To facilitate full automation, the processing flow is triggered automatically by existing hazard alert systems such as the USGS Earthquake Notification Service. Event monitoring through Vertex is based on technology developed within SARVIEWS through grant NNX12AQ38G. Visit the Events (SARVIEWS) documentation for more information.

+ +

Visit ASF's Vertex to begin using the Event search.

+ +
    +
  • When you select Event search type, a search will be performed, and all available events will be displayed. As with other search types, there are filters available to limit or refine your search results.
  • +
  • Click Event Search to enter an event name or partial name. You may also select the desired event from the drop down list displayed when you click the field.
  • +
  • Under Event Types, you can choose which event types you wish to be displayed. Currently, there are Earthquake and Volcano events.
  • +
  • You may select a Start Date or End Date.
  • +
  • Click Filters for more options
      +
    • You may toggle the Active Events Only switch to display only active events. The default is to display all events, including inactive events.
    • +
    • You may adjust the Magnitude slider to filter earthquakes by your desired magnitude range. Note: This filter applies only to earthquake events. If your search includes volcanoes, these will continue to be displayed in your search results.
    • +
    +
  • +
  • Once you have selected your desired Filters, click Search to update your search results.
  • +
+

Product Filters#

+
    +
  • Path and Frame Filters are available. You may enter a single path or frame, or a range.
      +
    • Click Clear to clear the entered path and frame values.
    • +
    • Note that Path and Frame will filter the displayed products within each event.
    • +
    +
  • +
  • Under Product Type, you may select one or more product types. This will filter the displayed products within each event.
  • +
+

Interacting with Event Search Results#

+

While in Event Search type, you will notice many familiar controls in the results panel. The events are shown in the left column. The Volcano and Earthquake icons note what type of event each result is. The center column lists the detail and metadata for the selected event. The Files for the selected event are shown in the right column.

+

Result Panel Controls

+
    +
  • At the top left of the results panel, you will see the number of events returned by your search.
  • +
  • Zoom will Zoom to results magnifying the map area of the Earth where the event is located.
  • +
  • Queue will Add all results to Downloads allowing you to add all event products to the download queue.
      +
    • You may choose to add All Event Products or Selected Event Products to the download queue. You may select individual files in the right column.
    • +
    +
  • +
  • Export will download the Bulk Download Script. This Python script allows you to download all products from the selected scene.
  • +
  • On Demand will allow you to Add all results to On Demand queue to do custom processing on the scenes. Depending on the types of files associated with the chosen event, you may be able to add RTC or InSAR jobs to your queue. To learn more click here.
  • +
  • Copy allows you to copy either the Scene IDs or the download URLs.
      +
    • You may choose to copy either All Scene IDs or URLs, or only copy Selected Scene IDs or URLs. You may select individual files in the right column.
    • +
    +
  • +
  • The Events column (left).
      +
    • Each event has either an earthquake or a volcano icon to the left of it, to help you quickly identify the event type.
    • +
    • Click Zoom to Event to magnify the map area of the Earth where the event is located.
    • +
    +
  • +
  • The Event Detail column (middle).
      +
    • The event details are listed here. This includes the event processing start and stop time. For earthquakes, the magnitude and depth is also displayed.
    • +
    • You may Copy the Event ID.
    • +
    • For earthquake events, the USGS ID is listed. For volcanoes, the Smithsonian ID is listed. Click the link to go to the USGS or Smithsonian event page.
    • +
    • Adjust the Geographic Search Polygon Scale slider as desired. The Area of Interest polygon will also update on the map.
    • +
    • Once you are happy with the Geographic Search Polygon Scale, click Geographic to launch a Geographic search using the event's Area of Interest & dates.
    • +
    • Click List to launch a list search including all of the event's product scenes.
    • +
    • The eye icon labeled Open in Image Viewer opens a larger browse viewer window.
        +
      • Note: When viewing InSAR images in the image viewer, the wrapped browse image is displayed. The unwrapped browse image is available in the downloaded product.
      • +
      • In the browse viewer, zoom using the + or - buttons. You may also zoom and pan using the mouse.
      • +
      • Click or scroll through the thumbnails at the bottom to see other browse images for the selected event.
      • +
      • The scene metadata is listed on the right side of the browse viewer window.
      • +
      • Under File, you may click the button labeled RTC GAMMA or INSAR GAMMA for more options
          +
        • Click Download File to download the selected product.
        • +
        • Click Add file to queue to add it to your Download queue.
        • +
        • Click Reference Scenes to copy the reference scene names to the clipboard. These may be saved in a file or used in List Search.
        • +
        • Click Pin Browse to Map to pin the browse image to the map. Once pinned, you may click this button again to unpin.
        • +
        +
      • +
      +
    • +
    • Click the Download this image icon to download the browse image.
    • +
    • Click the Pin icon to pin the selected browse image to the map. Once pinned, you may click this button again to unpin.
    • +
    +
  • +
  • The Files column (right).
      +
    • The total number of files for the selected event is listed in this column.
    • +
    • You may sort the files using the Sort By and Order buttons at the top of the column.
        +
      • Under Sort By, you may choose Date, Path, or Frame.
      • +
      • Click the Order Arrow to switch between ascending and descending order.
      • +
      +
    • +
    • Click Product Criteria to open the Search Filters.
    • +
    • Click the checkboxes next to each file to select or deselect the file. The selected files will be pinned onto the map. Once your desired files are selected, you may also use the Download or Copy controls in the top left of the results panel to interact with selected products.
    • +
    • Click On Demand to add the selected file to your On Demand queue for further processing.
    • +
    • Click the Shopping Cart icon to add the selected file to your Download queue.
    • +
    • Click Download to download the selected file.
    • +
    • Note: You must be logged in to download products.
    • +
    +
  • +
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/vertex/manual.key b/vertex/manual.key new file mode 100644 index 0000000..7394fbf --- /dev/null +++ b/vertex/manual.key @@ -0,0 +1 @@ +{{ VERTEX_MANUAL_1 }} \ No newline at end of file diff --git a/vertex/manual/index.html b/vertex/manual/index.html new file mode 100644 index 0000000..a45aadf --- /dev/null +++ b/vertex/manual/index.html @@ -0,0 +1,2180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Vertex Getting Started User Guide - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Vertex Getting Started User Guide#

+
    +
  • If you do not already have one, create a free Earthdata Login account.
  • +
  • Go to Vertex
      +
    • Log in by clicking the Sign in icon in the top right of the window. Use your Earthdata Login username and password. +
    • +
    +
  • +
  • Search Type allows you to choose between all available search types.
  • +
+

Language Options#

+

In the top right menu, next to the Sign In icon, there are language control options. Vertex currently offers English and Spanish. If your browser is set to one of the available languages, Vertex will default to that language. You may click the button and select your desired language from the drop down list. You may also set a default language in your Preferences.

+

Geographic Search Options#

+

+
    +
  • In the top left corner of the map, there are buttons that allow you to change your map view, zoom, and layers.
      +
    • By default, the map is in equatorial projection. You may click Map View and select Arctic map view or Antarctic map view to change your map projection. Click Equatorial map view to switch back to the equatorial projection.
    • +
    • You may click the Zoom In or Zoom Out icons to adjust your zoom.
    • +
    • The default map layer is satellite. You may click the Layers button and select Satellite View or Street View to switch your map layer.
        +
      • You may click Overview Map to add an overview map in the top right corner of the map. Click it again to turn off the overview map.
      • +
      • You may click Coherence Layer to select a seasonal coherence layer. Click the bubble next to the season you would like to turn on. Click the Coherence Layer checkbox again to turn the layer off.
      • +
      • You may click Gridlines to add a graticule overlay to the map. Click it again to turn off the overlay. Note: This is currently only available in the equatorial map view.
      • +
      +
    • +
    • You may click Opacity and adjust the slider as desired to change the opacity of browse images displayed on the map. If the Coherence Layer is on, you may also adjust the opacity of that layer.
    • +
    +
  • +
  • Navigate to your area of interest by dragging the map while holding down the left mouse button.
  • +
  • By default, the map-drawing tool is a bounding box. Click on the map once to specify the starting corner, move the mouse, then click again to finish the box. Additional drawing tool options are available in the toolbar at the top of the screen, including point, linestring, and polygon options.
      +
    • Point allows you to define an area of interest by clicking on the map to place a point.
    • +
    • Line allows you to define an area of interest over a series of line segments by clicking on the map multiple times. Double-click to stop adding segments.
    • +
    • Polygon allows you to define an area of interest over an arbitrary polygon. You will receive an error message at the bottom of the window if there was a problem with the polygon (self-intersecting, reversed polygon winding order, etc.).
    • +
    • Box allows you to define an area of interest over a lat/long-aligned bounding box by clicking once to set one corner, and again to set the opposite corner.
    • +
    • Circle allows you to define an area of interest over an arbitrary circle. Click and drag to select your circle. Click again to stop drawing.
    • +
    • Once a shape has been drawn, select the Edit current area of interest icon on the toolbar to move, add, and delete points. Select the Draw new area of interest icon to create a new AOI.
    • +
    • Clicking Upload Goespatial File brings up the Area of Interest dialog window. You may enter a WKT string, upload a geospatial file, or enter a location.
    • +
    +
  • +
  • Dataset enables you to choose the dataset of interest.
      +
    • If you need more information about a particular dataset, click on the appropriate question mark icon in the Dataset selector.
    • +
    +
  • +
  • Filters... enables you to further refine your search
  • +
+

Area of Interest Options#

+
    +
  • Area of Interest gives you the option of entering a set of geographic coordinates, importing an area of interest as a geospatial file, or searching for a location. Click on the down arrow next to Area of Interest in the top menu.
      +
    • An area of interest may be defined by a set of coordinates entered in the Area of Interest WKT window.
        +
      • Coordinates should be entered as decimal degrees in well-known text (WKT) format. Coordinates entered as a comma-separated long/lat string (e.g. -97.38,36.46,-53.44,36.46...) will be automatically converted by Vertex to WKT format.
      • +
      +
    • +
    • To upload a geospatial file, click Select Files and navigate to a folder on your computer, or drag and drop files into the box. GeoJSON, shapefiles, and KML files are supported provided they are in a latitude/longitude-based coordinate system, such as WGS84.
        +
      • When importing a GeoJSON file, all geometries in the file will be included. If multiple geometries are found, a convex hull will be used to represent them in the search.
      • +
      • Shapefiles can be either a single .shp file, multiple shapefile components (.shp, .shx, .dbf), or a zip file containing one or more shapefile components. At a minimum, the .shp component must be included in all cases.
      • +
      +
    • +
    • To enter a location, click the Search for a Location field, and start typing the name of the location. Select your desired location from the drop down list.
        +
      • Once you have selected a location, it will be geocoded into WKT format coordinates.
      • +
      +
    • +
    • You can save the coordinates of a search so they can be used to exactly recreate an area of interest in later searches.
        +
      • Once the Area of Interest has been set, a Copy to clipboard icon will appear. Click on the icon and paste the coordinates into a new search or to a text file for later use.
      • +
      • Note: See the section Other Vertex Options for additional ways of saving searches.
      • +
      +
    • +
    • At any time you can clear your search area by clicking on the Clear button.
    • +
    +
  • +
+

Shape Validation#

+

If the AOI specified is its own Minimum Bounding Rectangle (MBR) in a mercator projection, the search results returned will instersect with the AOI in a mercator projection, regardless of width. This remains the case even if the international dateline is crossed within the AOI.

+

In order for an AOI to be considered its own MBR, it must meet the following criteria:

+
    +
  • Each vertex shares a latitude or longitude with its neighbors
  • +
  • East/West points share longitude
  • +
  • North/South points share latitude
  • +
+

AOIs that do not fit this criteria will have their points connected along great circles.

+

In addition, all AOIs are validated, and then simplified as needed. The process for this is:

+
    +
  1. Validate the input AOI. If it is not valid, an error is displayed.
  2. +
  3. Merge overlapping shapes.
  4. +
  5. Convex hull.
  6. +
  7. Any out-of-range index values are handled by clamping and wrapping them to the valid range of values.
  8. +
  9. Simplify points based on proximity threshold. The target is fewer than 400 points.
  10. +
+

Each of these steps is performed only when necessary to get the AOI to a single outline with fewer than 400 points. Any unnecessary steps are skipped.

+

Examples of validation and simplification:

+
    +
  • A self-intersecting polygon is provided:
      +
    • An error is displayed.
    • +
    +
  • +
  • A single outline is provided, consisting of 1000 points:
      +
    • A simplified version of the same outline is used, consisting of fewer than 400 points.
    • +
    +
  • +
  • Multiple geometries are provided, all of them overlapping at least in part:
      +
    • A single outline is returned, representing the outline of all the shapes combined.
    • +
    +
  • +
  • Multiple geometries are provided, at least some of them entirely non-overlapping:
      +
    • A single outline is returned, representing the convex hull of all the shapes together.
    • +
    +
  • +
+

Date Filters#

+
    +
  • Date Filters Search dates are optional, so they default to empty. If you are searching for specific dates, you can define the date range further in the Start Date and End Date fields. The date picker will automatically constrain your selection to a valid range for the selected dataset.
      +
    • Note: this information may also be found by clicking on the question mark icon for a dataset.
    • +
    • Seasonal Search allows constraining the search to certain annual periods within an overall range of dates. Click the Seasonal Search toggle and additional options will appear, allowing you to enter an overall date range (Start Date/End Date) and the seasonal range (Season Start Day/Season End Day).
    • +
    +
  • +
+

Additional Filters#

+

+
    +
  • Additional Filters allow for additional parameters to be applied to narrow your search and reduce the number of results. Not all filters will be available for all datasets.
      +
    • File Type – Limit the search to specific types of files. Multiple selections allowed.
    • +
    • Beam Mode – Limit the search to specific beam modes. Multiple selections allowed.
    • +
    • Polarization – Limit the search to specific polarizations. Multiple selections allowed.
    • +
    • Direction – Limit the search to a specific orbit direction.
    • +
    • Subtype – Limit the search to a specific mission spacecraft.
    • +
    • Group ID – Limit the search to a specific group ID.
    • +
    • Burst ID – Limit the search to a specific burst ID. Multiple burst IDs allowed.
    • +
    • Standard Products or CalVal Products – Limit the search to either CalVal or Standard products. May choose one option. This selector is only available for the Opera-S1 dataset.
    • +
    • Campaign Selector – Limit the search to a specific campaign.
    • +
    +
  • +
+

Path and Frame Filters#

+
    +
  • Path and Frame Filters are available for select datasets. You may enter a single path or frame, or a range. Due to inconsistent Sentinel-1 framing, we recommend searching for a frame of interest by ±1-2 frames.
  • +
+

Additional Search Options#

+
    +
  • The maximum number of results is displayed below the SEARCH button. Click the down arrow to choose your preferred maximum results.
  • +
  • To clear all current search filters, click the down arrow next to the SEARCH button, then click Clear Search.
  • +
  • Once all parameters have been chosen, click SEARCH. Search results will appear in the footer area of the Vertex window and on the map.
      +
    • Note: The number of files that are predicted to match the current search parameters is displayed under the SEARCH button. If there are no predicted matches, the search button will be greyed out and display NO RESULTS.
    • +
    +
  • +
+

List Search Options#

+

+
    +
  • Selecting List Search opens the List Search window and allows you to enter a list of scenes or file names.
      +
    • Scene allows searching for specific scene names (granule names), and the results will include any files that are part of those scenes.
    • +
    • File allows searching for specific file names (product names), and the results will only include exactly those files.
    • +
    +
  • +
  • Edit List opens the List Search window so you can make changes to your list
  • +
  • Once all parameters have been chosen, click SEARCH. Search results will appear in the footer area of your browser window and on the map.
      +
    • Note: The number of files that are predicted to match the current search parameters is displayed under the SEARCH button. If there are no predicted matches, the search button will be greyed out and will display NO RESULTS.
    • +
    +
  • +
+

List Search File Import#

+

You may drag and drop files into the box provided on the Scene or File tabs. Each tab lists the file types accepted at the bottom. Vertex will parse the scene or file names from your uploaded file.

+
    +
  • +

    Note: Each file type requires a specific format. Files exported from Vertex will have the correct format.

    +
  • +
  • +

    CSV requires a column labeled "Granule Name" for a scene list search. It requires an additonal "Processing Level" column for a file list search.

    +
  • +
  • GeoJSON requires a field labeled "granuleName" for scene list search. It requires a field labeled "fileID" for file list search.
  • +
  • Metalink requires a structure formatted as
  • +
+
<metalink>
+    <files>
+        <file name="[Scene-Name.zip]"></file>
+        <file name ="...
+        ...</file>
+    </files>
+</metalink>
+
+
    +
  • KML requires a structure formatted as
  • +
+
<kml>
+    <Document>
+        <Placemark>
+            <name>[Scene Name]</name>
+        </Placemark>
+    </Document>
+</kml>
+
+

Baseline Search Options#

+

+
    +
  • Selecting Baseline Search provides a space to enter the name of a Reference Scene, and will then search for all secondary scenes that match the coverage area of the Reference.
      +
    • Note: If there are no matching scenes, the RESULTS button will be greyed out and will display NO RESULTS.
    • +
    +
  • +
  • Once a Reference Scene has been entered, click SEARCH. Search results will appear under the map. Clicking on the Zoom to results icon at the top of the left results column will display the location of the stack of scenes on the map.
  • +
  • The graph displays the Temporal and Perpendicular (spatial) relationship of the secondary scenes to the Reference.
  • +
  • The Baseline Criteria... button allows you to specify additional criteria to refine your results, such as start and end dates, seasonal date settings, and temporal and perpendicular extents.
  • +
  • For further information on Baseline, please see the Baseline documentation.
  • +
+

SBAS Search Options#

+

+
    +
  • Selecting SBAS Search provides a space to enter the name of a Reference Scene, and will search for all secondary scenes that match the coverage area of the Reference. It is an alternate method used for Interferometric SAR (InSAR) processing, similar to Baseline.
      +
    • Note: If there are no matching scenes, the RESULTS button will be greyed out and will display NO RESULTS.
    • +
    +
  • +
  • Once a Reference Scene has been entered, click SEARCH. Search results will appear under the map. Clicking on the Zoom to results icon at the top of the left results column will display the location of the stack of scenes on the map.
  • +
  • The chart displays the Temporal and Perpendicular (spatial) relationship of the secondary scenes to the Reference.
      +
    • Zoom In and Zoom Out buttons are available above the chart.
    • +
    • The Zoom to Fit button ensures that all pairs are visible on the chart.
    • +
    • The Custom Pair buttons allow you to add or delete a custom pair.
    • +
    • The SBAS Criteria... button allows you to specify additional criteria to refine your results, such as start and end dates, seasonal date settings, and latitudinal overlap threshold settings.
    • +
    +
  • +
  • For further information on SBAS, please see the SBAS documentation.
  • +
+

Event Search Options#

+
    +
  • Selecting Event allows you to view and search the products created for hazard monitoring.
  • +
  • Event Search allows you to enter an event name. You may enter the full name or a partial string.
  • +
  • Event Types allows you to filter which types of events you wish to see. Currently, there are earthquake and volcano events.
  • +
  • Start Date and End Date allow you to specify a date range for events.
  • +
  • Additional options may be found under Filters.
      +
    • You may toggle the Active Events Only switch to display only active events. The default is to display all events, including inactive events.
    • +
    • You may adjust the Magnitude slider to filter earthquakes by your desired magnitude range. Note: This filter applies only to earthquake events. If your search includes volcanoes, these will continue to be displayed in your search results.
    • +
    +
  • +
  • For further information on Event search, please see the Event Search documentation.
  • +
+

On Demand Products Search Options#

+
    +
  • Selecting On Demand Products allows you to view your submitted On Demand jobs. Note: You must be signed in to access this. If you are not signed in, this search option will be greyed out and you will not be able to select it.
  • +
  • Project Name allows you to limit your search to a specific project name. As you start typing, auto-complete options will become available with the project names you have previously used.
  • +
  • Date Filters Search dates are optional, so they default to empty. If you are searching for specific dates, you can define the date range further in the Start Date and End Date fields. Note: These dates filter by the scene date, not the date it was processed.
  • +
  • Product/Source Scene allows you to enter the product name or source scene name to limit your search. This field will also accept a partial string from either the product or source scene in lieu of the full name.
  • +
  • Job Status allows you to limit your search to specific statuses. Multiple selections allowed.
  • +
  • Note: Jobs expire 14 days after you submit them. Expired products still appear in search results, however, you may no longer download or add them to your cart. You can easily identify your expired products by the Expired tag next to the product name.
  • +
  • For further information on On Demand Products, please see the documentation.
  • +
+

Derived Datasets Search Options#

+
    +
  • Selecting Derived Datasets allows you to view and download products from ASF's catalog of datasets.
  • +
  • Each dataset listed includes a short description.
  • +
  • Click More Info to view more information about the dataset.
  • +
  • Click Download to view and download available products for your chosen dataset. Note: The download link will open in a new browser window.
  • +
  • For further information on Derived Datasets, please see the Derived Datasets documentation.
  • +
+

Search Results#

+

+
    +
  • In Vertex, a scene is considered to be a package containing all files, or products, that are related to a specific location and time.
      +
    • For example, the column on the left of the Results panel displays the scenes returned from a search. The column on the right displays the file contents of each scene.
    • +
    +
  • +
  • The maximum number of files that a search will return is displayed under the SEARCH button.
      +
    • This number can be adjusted by clicking on the down arrow.
    • +
    • The total number of files that match the search parameters is also displayed.
    • +
    +
  • +
  • The Results header bar.
      +
    • The Zoom button will zoom-in to the location of all scenes on the map.
    • +
    • The Queue button will add all scenes to the download queue.
    • +
    • The On Demand button will allow you to choose which eligible scenes to add to the On Demand Queue for further processing.
    • +
    • The Raw button will show or hide raw files. Note: This button is applicable for Sentinel-1 scenes only.
    • +
    • The Export or Pairs button will allow you to export data or metadata for all scenes in the results.
    • +
    • The Expired button will show or hide expired On Demand files. Note: This button is only available in the On Demand Products search type.
    • +
    • The Copy button will allow you to copy scene IDs or URLs. Note: This button is only available in the Event search type.
    • +
    • Note: Not all buttons are available on all search types.
    • +
    +
  • +
  • The Scenes column (left).
      +
    • Click on the cart icon next to a scene name to add all the scene’s files to the download queue. The cart changes appearance when this is done.
    • +
    • Click on the zoom icon next to a scene name to zoom-in to the scene’s location on the map.
    • +
    • Click the On Demand button to add eligible scenes to the On Demand Queue for further processing.
    • +
    +
  • +
  • To view more information about a scene, click on the scene in the left column and the Scene Detail and Files columns will populate.
      +
    • The Scene Detail column (center) provides a more detailed description of the scene, including Start Date/Time, Beam Mode, Path, Frame, Flight Direction, Polarization, Absolute Orbit, and a browse image (if available). Not all scenes will have all the extra information.
        +
      • The Baseline button opens the ASF Baseline Tool, which is used for creating InSAR stacks.
      • +
      • The SBAS button opens the ASF SBAS Tool, which is another method of creating InSAR stacks.
      • +
      • The More Like This button creates a search based on the selected scene’s path and frame. +
      • +
      • The Source Data button creates a search for the source Sentinel-1 scene based on the Opera product’s Group ID. Note: This button is only available for Opera-S1 search results.
      • +
      • The Citation button opens a new window with citation guidance for published works using data, imagery, or tools accessed through ASF.
      • +
      • Download this Image downloads the browse image.
      • +
      • The eye icon labeled Open in Image Viewer opens a larger browse viewer window.
          +
        • In the browse viewer, zoom using the + or - buttons. You may also zoom and pan using the mouse.
        • +
        • Click or scroll through the thumbnails at the bottom to see other browse images for scenes returned by your search.
        • +
        • By default, the Only display scenes with a browse image box is checked. You may uncheck this to see all scenes returned by your search. Scenes without a browse image will show a thumbnail listing No Browse Available.
        • +
        • The scene metadata is listed on the right side of the browse viewer window.
        • +
        • Click on a file to download immediately or add it to the download queue.
        • +
        +
      • +
      +
    • +
    • The Files column (right) displays a list of files available for the currently selected scene. You may download files immediately or add them to your download queue by clicking on the appropriate icon. You may also add eligible files to the On Demand queue for further processing.
    • +
    +
  • +
+

On Demand Queue#

+

+
    +
  • Clicking on the three boxes icon in the header, labeled On Demand, will display a drop down list of options.
  • +
  • On Demand Queue will open the On Demand queue.
      +
    • The different job types in your queue are separated by tabs along the top of the queue. You may click on a tab to select it. The selected tab is highlighted.
    • +
    • Some job types have additional processing options available. The options you select will apply to all files of that job type in your queue.
        +
      • You may hover over each option to display a tool tip with details on the option.
      • +
      +
    • +
    • Choose your desired sorting with the Sort Criteria and Sort Order drop-down boxes.
        +
      • Under Sort Criteria, you may choose to sort files by Start Date of the file, or by Date Added to the queue.
      • +
      • Under Sort Order, you may choose to sort files by Latest or most recent, or by Oldest.
      • +
      +
    • +
    • The list of files you have added to your queue is listed below the options. The X allows you to remove any files you wish from the queue.
    • +
    • Clear will list some options for clearing files from your queue. You can choose to clear an individual tab, or you can choose Clear All Processing Types to clear all files from the queue. If you choose to clear all files, the option Restore will be displayed to allow you to undo this action.
    • +
    • The number of credits remaining is displayed at the bottom of the queue. Each job type uses a set amount of credits. The Submit button will list the total number of credits that your jobs will use. If you have too many jobs in your queue, the Submit button will be greyed out.
    • +
    • When you are satisfied with your selections, click Submit Jobs at the bottom. This will display the Review Submission window.
        +
      • The Project Name field allows you to create a name for the files you want to submit for processing. The character limit is 20. This field is optional.
      • +
      • You may select or deselect the checkboxes to submit only the job types you wish.
      • +
      • Select Cancel to return to the queue without submitting any files for processing.
      • +
      • Click Submit to submit your jobs. Note: The Submit button will list the number of jobs and the amount of credits you are submitting.
      • +
      • If there are any errors, such as missing DEM coverage, an error message will display.
      • +
      +
    • +
    +
  • +
  • Submitted Products will switch to On Demand Products search type and will display your submitted products.
  • +
  • On Demand (HyP3) Docs will send you to the On Demand documentation
  • +
  • Note: You must be signed in to see your Submitted Products and to submit jobs from the On Demand Queue.
  • +
+

Downloads Queue#

+

+

Enhanced download queue functionality is now available on Google Chrome browser. See below for more information.

+
    +
  • Clicking on the cart icon in the header, labeled Downloads, will display the contents of your current download queue.
      +
    • Within the download queue, the list of files you have selected to download is displayed with some basic information on each file, such as file type and size.
        +
      • File IDs (names) can be copied with the copy icon.
      • +
      • Files can be individually downloaded with the cloud icon. You may also right click to save or copy the download URL.
      • +
      • Items can be removed from the queue with the X.
      • +
      +
    • +
    • Clear will clear all files from the queue. The option Restore will be displayed to allow you to undo this action.
    • +
    • Copy File IDs will copy the file names of all files in the queue for use elsewhere. For example, this list could then be pasted into the List Search window.
    • +
    • Copy URLs will copy the download URLs of all files in the queue.
    • +
    • Data Download is used to download multiple products, with either the Download Python Script (.py) option or Metalink (metalink) file option.
    • +
    • Metadata Download is used to export the contents of the download queue to a CSV, KML, or GeoJSON file. The KML and GeoJSON files provided by this feature are compatible with the Geographic Search Import feature.
    • +
    +
  • +
+

Google Chrome Browser#

+

Enhanced download queue functionality is available on Google Chrome browser. Please note, this improved functionality is not supported while using incognito mode.

+
    +
  • Click on the cart icon in the header, labeled Downloads to open your download queue.
      +
    • Next to each file, you may click the cloud icon to begin the download.
        +
      • As the download begins, a progress indicator lists the percentage downloaded. Once the dowload has completed, the icon appears as a check mark to indicate the file has been downloaded.
      • +
      • While the file is downloading, you may click the progress indicator to stop the download.
      • +
      +
    • +
    • Under Data Download, you may select Download All. This will download 3 files at a time until all products in your cart have been downloaded. The same progress indicators and checkmarks will be displayed to let you know the status of each download in your queue.
        +
      • When you click Download All, a dialog box will appear:
          +
        1. Navigate to the folder where you wish to save the files and click Select.
        2. +
        3. Click View Files to allow the download to continue.
        4. +
        5. Click Save Changes to save your download folder preferences. This will persist as long as the Vertex browser window remains open.
        6. +
        +
      • +
      +
    • +
    • If you Clear the products in your queue, the download progress and completion indicators will reset. You may add the products to your queue again if desired.
    • +
    • Note: You must be signed in to download files. If you are not signed in, when you click to begin a download, you will be redirected to the sign in page first.
    • +
    +
  • +
+

Other Vertex Options#

+
    +
  • In the top left corner of the map, there are buttons that allow you to change your map view, zoom, and layers. Note: Available map controls vary by search type. +
      +
    • By default, the map is in equatorial projection. You may click Map View and select Arctic map view or Antarctic map view to change your map projection. Click Equatorial map view to switch back to the equatorial projection.
    • +
    • You may click the Zoom In or Zoom Out icons to adjust your zoom.
    • +
    • The default map layer is satellite. You may click the Layers button and select Satellite View or Street View to switch your map layer.
        +
      • You may click Overview Map to add an overview map in the top right corner of the map. Click it again to turn off the overview map.
      • +
      • You may click Coherence Layer to select a seasonal coherence layer. Click the bubble next to the season you would like to turn on. Click the Coherence Layer checkbox again to turn the layer off.
      • +
      • You may click Gridlines to add a graticule overlay to the map. Click it again to turn off the overlay. Note: This is currently only available in the equatorial map view.
      • +
      +
    • +
    • You may click Opacity and adjust the slider as desired to change the opacity of browse images displayed on the map. If the Coherence Layer is on, you may also adjust the opacity of that layer.
    • +
    +
  • +
  • Click on the down arrow on the Search
      +
    • Clear Search will clear all search parameters that have been set except for Search Type and Dataset.
    • +
    • Saved Searches opens a submenu. Note: You must be signed in to Vertex for this option to be available. +
        +
      • Save Search allows you to name and save your current search.
      • +
      • View Searches... opens a list of searches that you have named and saved. Click on the magnifying glass icon to load the search settings.
      • +
      • Search History... opens a list of your 10 last searches that were not named and saved. Click on the magnifying glass icon to load the search settings.
      • +
      +
    • +
    • Saved Filters opens a submenu. Note: You must be signed in to Vertex for this option to be available.
        +
      • Save Filters allows you to save your current filter set.
      • +
      • View Filters... allows you to view your saved filter sets. Click Apply Filters to apply them to your current search.
      • +
      +
    • +
    • Share Search opens a submenu.
        +
      • Copy Search Link will copy all the search parameters that have been set in the current search as a URL. The URL can then be pasted into a browser search bar to recreate the search exactly, or pasted into a document and saved to recreate the search later.
      • +
      • Share With Email will open a new email with the URL of the search to send to others.
      • +
      +
    • +
    • Help & Tutorials provides both illustrated and video demonstrations on a variety of topics.
    • +
    • Export opens a submenu.
        +
      • Export Python will provide a Python code snippet to recreate the current search using the Python search package asf_search. It also provides a link to the asf_search documentation.
      • +
      • Export API will provide the API URL to recreate the current search using the SearchAPI. It also provides a link to the SearchAPI documentation.
      • +
      +
    • +
    +
  • +
  • Click Help for additional help options.
      +
    • Watch Our Tutorials provides both illustrated and video demonstrations on how to use Vertex.
    • +
    • Read Our User Guide opens the Vertex documentation in a new tab.
    • +
    • Read Our On Demand Guide opens the On Demand documentation in a new tab.
    • +
    • Find SAR Data Using ASF API opens the SearchAPI documentation in a new tab.
    • +
    • Learn More About ASF & SAR opens the ASF website in a new tab.
    • +
    • Statistics and GitHub Repository provides links to our GitHub Vertex repository.
    • +
    +
  • +
  • Click the Language icon to select your default language.
  • +
  • Click on the Sign in icon once you are signed in to display the user options.
      +
    • Saved Searches opens a list of searches that you have named and saved. Click on the magnifying glass icon to load the search settings.
    • +
    • Search History opens a list of your 10 last searches that were not named and saved. Click on the magnifying glass icon to load the search settings.
    • +
    • Saved Filters opens a list of filters that you have saved. Click Apply Filters to apply the selected filter set to your search.
    • +
    • Preferences opens a window that allows you to set search preferences for language, theme, dataset, max results, map layer, default filter presets, and On Demand presets. These preferences will be saved and applied to future searches.
    • +
    +
  • +
  • Note: Saved Searches, Saved Filters, and Search History are available through both the Sign in menu and the Search button down arrow menu.
  • +
  • Click into the Search all ASF field on the grey header bar to perform a search. Inputs into this field will search across all ASF websites.
      +
    • You may also click the microphone icon if you prefer to use voice search.
    • +
    • As you type or speak, the results of your search will be displayed in a list below the field. Clicking a result from the list will open a new browser tab.
    • +
    • You may click the magnifying glass icon to expand the search results. This will open in the same browser window. To close and return to Vertex, click the X near the top right of your screen.
    • +
    +
  • +
+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/vertex/sbas.key b/vertex/sbas.key new file mode 100644 index 0000000..958bb77 --- /dev/null +++ b/vertex/sbas.key @@ -0,0 +1 @@ +{{ SBAS_1 }} \ No newline at end of file diff --git a/vertex/sbas/index.html b/vertex/sbas/index.html new file mode 100644 index 0000000..d76250f --- /dev/null +++ b/vertex/sbas/index.html @@ -0,0 +1,1620 @@ + + + + + + + + + + + + + + + + + + + + + + + + + SBAS - ASF SAR Data Search Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + +

SBAS Search Type#

+

What is SBAS?#

+

SBAS is an acronym for short baseline subsets. It is a technique used in interferometry. The Vertex SBAS tool provides perpendicular and temporal baseline data, as well as scene pairs, for a chosen reference scene.

+

What are some uses for SBAS?#

+

SBAS is widely used in the geosciences community. It works best for natural environments over a large scale and can be used to look at gradual change over time. SBAS requires input of a series of interferograms and the final output is a time series showing motion.

+

One advantage of SBAS is that you are not restricted to a single interferogram. You can see gradual changes over time. It can also be useful for older datasets which sometimes have irregular acquisitions. The temporal and spatial filtering can help increase the accuracy for measuring deformation.

+

You must choose which interferograms to use, which can require some experimentation. The Vertex SBAS tool simplifies this by providing good visualization and making it easier for you to quickly determine which scenes to use.

+

There are other preferred approaches for urban environments, or higher resolution needs. However, regardless of your analysis needs, the SBAS tool is a useful overview tool and can also be used as a 2-D baseline plot. It gives a comprehensive, but rapid visualization of scenes.

+

Further reading on baseline, including descriptions of multiple approaches, can be found here. A case study comparison of PS and SBAS can be found here.

+

How to use Vertex SBAS Tool#

+

Visit ASF's Vertex to begin using the SBAS tool. +

+ +
    +
  • +

    If you do not have a particular reference scene chosen, you can search for scenes using the geographic or list search. The center column will have a button under the metadata titled SBAS Tool for any scenes that are eligible. You may click this button to be directed to an SBAS search. The SBAS search will use the chosen scene as the reference scene.

    +
  • +
  • +

    If you do have a particular reference scene chosen, you can select SBAS from the Search Type dropdown list. You may enter your reference scene and hit Search.

    +
  • +
+

Interacting with SBAS Search Results#

+

While in SBAS Search type, you will notice many familiar controls in the results panel. The pairs are shown in the left column. The center column lists the metadata for the two endpoints of the selected pair. The SBAS Chart is shown in the right column.

+

Result Panel Controls

+
    +
  • At the top left of the results panel, you will see the number of pairs listed.
  • +
  • Zoom will Zoom to results magnifying the map area of the Earth where the scenes are located.
  • +
  • Queue will Add all to Downloads allowing you to add all scenes to the download queue.
  • +
  • On Demand will allow you to Add all to On Demand queue to perform custom processing on the scenes.
      +
    • You may choose from the available job types available for your scenes, depending on your needs. RTC processing is performed on the individual scenes in your result set. InSAR and autoRIFT processing are performed on the pairs in your result set.
    • +
    • Note: Currently, only scenes with beam mode IW are eligible for On Demand processing.
    • +
    +
  • +
  • Pairs will Download Pair CSV which lists the scenes in each pair and the download URL for each. It also includes the baseline values.
  • +
  • In the left column, highlight the desired pair and click the On Demand icon to Add pair to On Demand queue. You may choose your desired job type for each pair.
  • +
+

Chart Controls

+
    +
  • The dots on the chart represent individual scenes. Hovering over them will list their temporal and perpendicular information. The lines represent the pairs.
  • +
  • You may use the mouse to navigate the chart. There are Zoom In and Zoom Out buttons located above the chart. The Zoom to Fit button will fit all of the pairs into the visible chart.
  • +
  • You may click on any pair line in the chart. When you do, the selected pair is highlighted in red and the metadata for that pair is shown in the center column.
  • +
  • You may adjust the temporal and perpendicular baseline using the sliders on the chart.
  • +
  • You may also create your own pair if desired:
      +
    1. Under Custom Pair, click the Plus symbol to Start adding custom pair.
    2. +
    3. Click the dot on the chart representing the first scene.
    4. +
    5. Click the dot on the chart representing the second scene.
    6. +
    7. The new pair is created, and the pair detail is added to the bottom of the result list. Manually added pairs will be displayed with a dotted line on the chart.
    8. +
    9. Note: You may also add custom pairs to the On Demand queue.
    10. +
    +
  • +
  • If you wish to stop adding a pair after you have begun, you may click the Square symbol to Stop adding custom pair.
  • +
  • If you wish to delete an added pair, you may click on the dotted pair line and click the Minus symbol to Remove custom pair. Note that only manually added pairs may be deleted.
  • +
+

Gaps Detected Warning Message#

+

If there are gaps detected in your SBAS pairs, a warning message will be displayed. It is recommended to avoid disconnected InSAR pair networks. Disconnected pair networks make it difficult to create unbiased estimates of InSAR velocities within a time-series analysis.

+

If you wish to eliminate the gaps, you may modify your search filters, such as increasing the temporal baseline until all scenes are connected. You may also add manual pairs for the missing connections. Once all scenes have at least one connection, the warning message will disappear.

+

SBAS Criteria#

+
    +
  • Click SBAS Criteria... for additional filtering options.
      +
    • You may enter a Start or End date, or select dates on the calendar.
    • +
    • Seasonal Search allows constraining the results to certain annual periods within an overall range of dates. Click the Seasonal Search toggle and additional options will appear, allowing you to adjust the sliders to specify a seasonal range (Season Start Day/Season End Day).
    • +
    • Latitudinal Overlap allows you to set the overlap threshold for pairs. Filtering out non-overlapping pairs can reduce errors in On Demand InSAR processing.
        +
      • No Overlap Threshold is the default. All pair results are returned, including any non-overlapping pairs.
      • +
      • Any Overlap Threshold will ensure that all pairs have some overlap. Any non-overlapping pairs will be filtered out of the results.
      • +
      • 50% Overlap Threshold ensures that all pairs have approximately 50% overlap. Any pairs with less overlap will be filtered out of the results.
      • +
      +
    • +
    +
  • +
+

Next Steps#

+

The next step is creating interferograms. You may do this through On Demand processing in Vertex. First, you would add some or all of the pairs to the On Demand queue as InSAR jobs. In the queue, there are limited options available for customizing your InSAR processing. You may also specify a project name. Submit the queue when you have selected all desired options. When the interferograms are completed, you can view and download them by using the On Demand Products search type in Vertex.

+

For areas with glacial ice, autoRIFT is another processing option. Similar to InSAR, you would add some or all pairs to the On Demand queue as autoRIFT jobs. There are no additional customization options available for autoRIFT processing, however you can still specify a project name. When autoRIFT processing is completed, you can view and download the products by using the On Demand Products search type in Vertex.

+

More detail can be found in the Vertex User Guide. Help documentation, including videos, is also available in Vertex here.

+

To learn more, you may also see the On Demand documentation.

+ + + + + + + + +
+
+ + +
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file

Comenzando su búsqueda inicial#