The purpose of this document is to delineate the processing steps used to join lake identifiers from 5 data products into a single lake identifier table called LAGOS Lake Link (working name).

Definitions in this document

“Lake”: Permanent lake or reservoir.

Entity-relationship diagram

Entity-relationship diagram

Entity-relationship diagram

Data Processing Pipeline

5 main datasets will be introduced to create the crosswalk: LAGOS (US), GNIS, WQP, NHDPlusV2 (medium-resolution), and LAGOS-NE. For each dataset, the workflow is as follows:

  1. Import. Modify fields and prepare the data frame for later work.
  2. Filter. We focus here on lakes and reservoirs in the continental United States. In order to preserve this focus, categories of entities that are less likely to represent one of these features are pruned away during this step, even if those categories sometimes connect to a LAGOS-US lake. The crosswalk only includes relationships if they ultimately connect back to a LAGOS-US lake. For example–even though you can use this table to walk between WQP sites and NHDPlusV2 lakes, the relationship is not comprehensive because lakes not found in LAGOS-US are missing.
  3. Convert between spatial and non-spatial data formats, as needed. Spatial formats are projected to the USGS Albers Conic Equal Area projection for consistency.
  4. Select only the necessary columns for the upcoming work.
  5. Join LAGOS-US to each other dataset, individually. This step may include spatial joins, joins on common identifiers. After joining, identifying fields may be flattened into a single concatenated field or coalesced.
  6. Select again again as needed before the final join.
Processing Pipeline

Processing Pipeline

Finally, the results of the multiple joins in step 4 will be merged into a single crosswalk table with only the necessary fields remaining.

LAGOS-US

The LAGOS-US lake population is the focal dataset of the LAGOS Lake Link crosswalk (top center, Figure ). We will connect all other datasets to this one in the crosswalk. Lakes will only This dataset is a subset of the NHD High Resolution NHDWaterbody layers (see “Filter” section for details) representing permanent, non-artificial LakePond and Reservoir waterbodies. Currently, LAGOS-US is under development and while the lake polygon dataset is completed, much of the database remains to be built in 2018 and 2019.

The primary identifier for lakes in this dataset is lagoslakeid. A secondary unique identifier is named nhdid in the “locus” table, which corresponds to the Permanent_Identifier in the NHD and in the GIS layer imported here.

Import

We’ll import the GIS polygon layer prepared for LAGOS-US. Glimpse the polygon layer:

Observations: 479,950

Filter

The LAGOS-US dataset has already been filtered from the source dataset of all NHDWaterbody features to generate the final target lake population. The code is not included but the processing rules are summarized below.

Criteria for selecting NHD lake polygons for inclusion in LAGOS-US were as follows. Included lakes must:

  • Be derived from snapshots of the NHD staged by subregion taken 2016-12-15, 2016-12-16, 2017-01-03 (HUC4 1019), 2017-01-03 (HUC4 0309, 1004, 1804).
  • Not be an exact duplicate of another NHD lake polygon.
  • If a duplicate of another lake except for FDate and Shape, then the lake retained must have the most recent FDate (feature edit date).
  • Intersect the LAGOS-US contiguous U.S. layer (48 states plus D.C., TIGER/Line data).
  • Be represented as simple features–we densified several features with only 2 vertices using 10 m as the maximum deviation for each vertex in order to “repair” their representation to match the majority and the standard.
  • Not be Great Lakes or the portion of Lake St. Clair (MI/ON) that is in Canada.
  • Have an AreaSqKm > 0.009 (AreqSqKm field included in original NHDWaterbody).
  • Have a polygon area greater than or equal to 1 hectare (calculated during LAGOS-US processing and measured in the Albers USGS Conic projection). The calculated area occasionally does not match the area in square kilometers provided by NHD.
  • Be assigned one of the following Feature Codes representing permanent water bodies and non-artificial water bodies:
    • 39000,39004,39009,39010,39011,39012 (lakes)
    • 43600,43613,43615,43617,43618,43619,43621 (reservoirs)
  • One lake in Mexico was removed (Permanent_Identifier = ‘e05e57b5-d29f-4e1e-8369-73e55f8be9df’) after independent verification of the lake processing workflow revealed a single discrepancy due to slight variations in order of when data projection was performed.

The number of LAGOS-US lakes after filtering is 479950.

Convert and Select

We will select several columns and create two alternate representations of the LAGOS-US dataset: centroids and no geometry.

lagos <- lagos_sf %>%
  select(lagoslakeid, 
         Permanent_Identifier, 
         GNIS_ID, 
         GNIS_Name, 
         ReachCode, 
         STATE, 
         AreaSqKm, 
         FDate,
         LAGOS_CountyName = NAMELSAD,
         LAGOS_CountyFIPS = FIPS)
lagos_centroid <- lagos_sf %>%
  st_centroid() %>%
  st_transform(NAD83) %>%
  mutate(LAGOS_LatitudeNAD83 = st_coordinates(.)[,'Y'], 
         LAGOS_LongitudeNAD83 = st_coordinates(.)[,'X']) %>%
  select(lagoslakeid, LAGOS_LatitudeNAD83, LAGOS_LongitudeNAD83)
lagos_df <- lagos %>% st_set_geometry(NULL)

GNIS (Geographic Names Information System)

The GNIS dataset contains place names for a variety of geographic features, including lakes, in the United States. Locations are represented as latitude/longitude pairs. Most NHD lakes already have a GNIS name assigned, but in some cases where lakes had multiple names, they were not assigned a name in the NHD. To populate the lake name as fully as possible, we searched the GNIS dataset to both add missing names where available and to document lakes with multiple names, which we then retain in LAGOS-US.

Import

Glimpse the original GNIS table.

Observations: 2,276,506
Variables: 20
$ FEATURE_ID      <int> 0, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412...
$ FEATURE_NAME    <chr> "Bruceville Cemetery", "Agua Sal Creek", "Agua Sal Wash", "Aguaje Draw"...
$ FEATURE_CLASS   <chr> "Cemetery", "Stream", "Valley", "Valley", "Park", "Stream", "Stream", "...
$ STATE_ALPHA     <chr> "CO", "AZ", "AZ", "AZ", "AZ", "AZ", "AZ", "AZ", "AZ", "AZ", "AZ", "AZ",...
$ STATE_NUMERIC   <chr> "08", "04", "04", "04", "04", "04", "04", "04", "04", "04", "04", "04",...
$ COUNTY_NAME     <chr> "Boulder", "Apache", "Apache", "Apache", "Maricopa", "Graham", "Apache"...
$ COUNTY_NUMERIC  <chr> "013", "001", "001", "001", "013", "009", "001", "019", "017", "005", "...
$ PRIMARY_LAT_DMS <chr> "400058N", "362740N", "363246N", "343417N", "331455N", "322815N", "3552...
$ PRIM_LONG_DMS   <chr> "1051226W", "1092842W", "1093103W", "1091313W", "1124625W", "1095610W",...
$ PRIM_LAT_DEC    <dbl> 40.01610, 36.46111, 36.54611, 34.57143, 33.24865, 32.47090, 35.87501, 3...
$ PRIM_LONG_DEC   <dbl> -105.2072, -109.4784, -109.5176, -109.2204, -112.7735, -109.9362, -109....
$ SOURCE_LAT_DMS  <chr> NA, "362053N", "362740N", "344308N", NA, "323048N", "354903N", "315820N...
$ SOURCE_LONG_DMS <chr> NA, "1090915W", "1092842W", "1085826W", NA, "1095233W", "1093001W", "11...
$ SOURCE_LAT_DEC  <dbl> NA, 36.34806, 36.46111, 34.71880, NA, 32.51340, 35.81750, 31.97230, 34....
$ SOURCE_LONG_DEC <dbl> NA, -109.1543, -109.4784, -108.9739, NA, -109.8759, -109.5003, -111.391...
$ ELEV_IN_M       <int> 1598, 1645, 1597, 1750, 231, 1339, 1799, 591, 1494, 1435, 1506, 81, 144...
$ ELEV_IN_FT      <int> 5243, 5397, 5239, 5741, 758, 4393, 5902, 1939, 4902, 4708, 4941, 266, 4...
$ MAP_NAME        <chr> "Niwot", "Fire Dance Mesa", "Little Round Rock", "Kearn Lake", "Spring ...
$ DATE_CREATED    <chr> "05/04/2015", "02/08/1980", "02/08/1980", "02/08/1980", "02/08/1980", "...
$ DATE_EDITED     <chr> "10/22/2015", NA, NA, "01/14/2008", NA, NA, NA, NA, NA, NA, NA, NA, NA,...

Filter

Included GNIS sites must:

  • Be within one of the 48 contiguous states or D.C (FIPS code match)
  • Be within the rough bounding box of the U.S. (eliminates a few spurious locations)
  • Be assigned the Lake or Reservoir Feature Class. These feature classes aggregate a variety of feature names such as Lake, Lakes, Reservoir, Pond, Tank, Slough, Millpond, etc. A prior analysis showed that nearly all GNIS names already assigned in the NHD correspond to one of these two classes, with minor use of Swamp, Flat, and rare use of a smattering of other feature classes. We choose to focus the crosswalk on the most relevant locations rather than conserve all possible links.
  • Not be assigned a “historical” site name. Such names are spatially coincident with the current name.

The number of GNIS sites for U.S. lakes is 138055.

Convert

According to the metadata, the coordinates use the NAD83 datum. Convert the XY data to points.

Select

Select the FEATURE_ID, FEATURE_NAME, and FEATURE_CLASS.

gnis <- gnis_sf %>%
  select(FEATURE_ID, FEATURE_NAME, FEATURE_CLASS)

Join LAGOS-US

First, join LAGOS-US to GNIS based on the shared GNIS_ID.

GNIS Names contained by the polygon are assigned to the lake. A new column, “LAGOS Lake Name” is created and multiple names for a lake are separated by semi-colons. This will eliminate the 1:many relationship created in the join.

Select again

Select only the desired names and identifiers.

lagos_gnis <- lagos_gnis_3 %>%
  st_set_geometry(NULL) %>%
  select(lagoslakeid, Permanent_Identifier, GNIS_ID, GNIS_Name, ReachCode, STATE, LAGOS_LakeName, AreaSqKm)

WQP (Water Quality Portal–STORET, NWIS, and more)

The WQP API allows queries of all water quality monitoring sites that are submitted to major national databases. Sites are described with identifiers, coordinates, and names, but are not definitively linked to any polygon representation of lakes to our knowledge. The goal here is to match the WQP identifiers with lakes in LAGOS-US.

Import

Glimpse the original WQP table.

Observations: 2,300,409
Variables: 36
$ OrganizationIdentifier                          <chr> "ARS", "ARS", "ARS", "ARS", "ARS", "ARS...
$ OrganizationFormalName                          <chr> "Agricultural Research Service", "Agric...
$ MonitoringLocationIdentifier                    <chr> "ARS-IASF-IABC264", "ARS-IASF-IABC274",...
$ MonitoringLocationName                          <chr> "IABC264", "IABC274", "IABC350", "IASF2...
$ MonitoringLocationTypeName                      <chr> "Land Runoff", "Land Runoff", "River/St...
$ MonitoringLocationDescriptionText               <chr> "A drainage ditch monitoring site on 19...
$ HUCEightDigitCode                               <chr> "07080207", "07080207", "07080207", "07...
$ DrainageAreaMeasure.MeasureValue                <dbl> NA, NA, 18210.0, NA, NA, NA, NA, NA, NA...
$ DrainageAreaMeasure.MeasureUnitCode             <chr> NA, NA, "ha", NA, NA, NA, NA, NA, NA, N...
$ ContributingDrainageAreaMeasure.MeasureValue    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ ContributingDrainageAreaMeasure.MeasureUnitCode <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ LatitudeMeasure                                 <dbl> 42.41918, 42.40710, 42.33911, 42.54317,...
$ LongitudeMeasure                                <dbl> -93.18051, -93.20679, -93.12500, -93.47...
$ SourceMapScaleNumeric                           <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ HorizontalAccuracyMeasure.MeasureValue          <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ HorizontalAccuracyMeasure.MeasureUnitCode       <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ HorizontalCollectionMethodName                  <chr> "GPS Code (Pseudo Range) Differential",...
$ HorizontalCoordinateReferenceSystemDatumName    <chr> "NAD83", "NAD83", "NAD83", "NAD83", "NA...
$ VerticalMeasure.MeasureValue                    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ VerticalMeasure.MeasureUnitCode                 <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ VerticalAccuracyMeasure.MeasureValue            <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ VerticalAccuracyMeasure.MeasureUnitCode         <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ VerticalCollectionMethodName                    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ VerticalCoordinateReferenceSystemDatumName      <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ CountryCode                                     <chr> "US", "US", "US", "US", "US", "US", "US...
$ StateCode                                       <chr> "19", "19", "19", "19", "19", "19", "19...
$ CountyCode                                      <chr> "083", "083", "083", "083", "079", "083...
$ AquiferName                                     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ FormationTypeText                               <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ AquiferTypeName                                 <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ ConstructionDateText                            <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ WellDepthMeasure.MeasureValue                   <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ WellDepthMeasure.MeasureUnitCode                <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ WellHoleDepthMeasure.MeasureValue               <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ WellHoleDepthMeasure.MeasureUnitCode            <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ ProviderName                                    <chr> "STEWARDS", "STEWARDS", "STEWARDS", "ST...

Filter

Included WQP sites must:

  • Be within the continental United States (rough cut to eliminate distant territories)
  • Be assigned one of the following Monitoring Location Types: “Lake”, “Reservoir”, “Riverine Impoundment”, “Lake, Reservoir, Impoundment”. These categories were selected in an analysis that assessed how often the sites of each type were located within an NHD polygon and whether they often had Secchi depth measurements, a characteristically limnological sampling parameter. Other location types did sometimes represent desirable samples, but we choose to focus the crosswalk on the most relevant locations rather than conserve all possible links. Stream, wetlands, estuaries and Great Lakes were categorically excluded despite meeting the above criteria in some part.

The number of WQP sites meeting these criteria is 131005.

Convert

There is a column in WQP data to indicate the coordinate reference system (CRS). However, not all sites had a value in this column. Prior analysis showed that the most commonly indicated column was NAD83, and so for all sites with an unknown or rare CRS (distant U.S. territories), the NAD83 datum was imputed instead.

For sites with one of the following other datums, the actual datum specification is preserved: NAD27, WGS84. In order to manage the projections before transforming all the data to a common projection, Albers Equal Area Conic (USGS), we split up the dataset, projected the sites in each datum, converted all rows to Albers USGS, and then reunited all rows at the end.

Select

wqp <- wqp_sf %>%
  select(OrganizationIdentifier, MonitoringLocationIdentifier, MonitoringLocationName, ProviderName, MonitoringLocationTypeName)

Join LAGOS-US

  1. WQP sites within a lake polygon are linked to that polygon.

Examination of shared words in the names: All lakes where two names are available but don’t share words. Some of these lakes have names following some kind of technical form, but others seems to suggest mis-referenced lakes even though the point for the site falls inside the lake. Some examples (zoom in to see NHD detail appear):

  1. WQP sites can be joined to a lake polygon if they are within 10 meters of it.
  1. Other sites can be joined if they are within 100 m of a lake polygon, not within an NHDArea StreamRiver feature, and share name words other than “lake”, “reservoir”, etc.

Join them all up into one and enforce the rules.

How many joins were made for each method?

  • No search distance: 91958
  • 10 m search distance: 5139
  • 100 m search distance (with name condition): 5267

Some lakes have a very high number of sampling sites. This map shows some examples of lakes with over 50 sampling sites stored.

Select again

Retain only columns relevant to crosswalk.

lagos_wqp <- lagos_wqp_all %>%
  st_set_geometry(NULL) %>%
  select(OrganizationIdentifier, MonitoringLocationIdentifier, MonitoringLocationName, ProviderName, Linked_lagoslakeid)

NHDPlusV2 (value-added National Hydrography Dataset and basis for National Lakes Assessment, LakeCat)

The medium-resolution NHD contains a popular medium-resolution representation of lakes and their hydrographic context. Because the high-resolution NHD data were used to generate LAGOS-US, we must find a connection between the datasets. This connection is the reach code, a 14-digit identifier used to identify each reach as part of a linear referencing system. ReachCodes must sometimes be modified (split, joined, re-assigned, deleted). The NHDReachCrossReference table tracks these changes and shows the new and old ReachCode.

Import

The version of the NHDReachCrossReference table that we use has already been filtered to include only the reach codes for lakes and reservoirs in the NHD HR (e.g. streams, wetlands, etc. were removed) to reduce the table size. You could use the full original table with no change to the results.

Glimpse the NHD table.

Observations: 448,512
Variables: 22
$ COMID        <int> 806161, 806167, 806169, 806175, 806179, 806181, 806183, 806189, 806197, 80...
$ FDATE        <dttm> 1999-05-27, 1999-05-27, 1999-05-27, 1999-05-27, 1999-05-27, 1999-05-27, 1...
$ RESOLUTION   <chr> "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Med...
$ GNIS_ID      <dbl> NA, NA, 564483, 563828, 575611, NA, NA, NA, NA, 572518, NA, NA, 563822, NA...
$ GNIS_NAME    <chr> " ", " ", "Cranberry Pond", "Chandler Lake", "Smith Brook Pond", " ", " ",...
$ AREASQKM     <dbl> 0.013, 0.055, 0.176, 1.572, 0.069, 0.162, 0.136, 0.187, 0.049, 0.018, 0.01...
$ ELEVATION    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
$ REACHCODE    <chr> "01010004001814", "01010004001819", "01010004001817", "01010004001854", "0...
$ FTYPE        <chr> "LakePond", "LakePond", "LakePond", "LakePond", "LakePond", "LakePond", "L...
$ FCODE        <int> 39004, 39004, 39004, 39004, 39004, 39004, 39004, 39004, 39004, 39004, 3900...
$ Shape_Length <dbl> 0.005468933, 0.021807035, 0.021755760, 0.087375064, 0.017330298, 0.0530475...
$ Shape_Area   <dbl> 1.513469e-06, 6.416618e-06, 2.057280e-05, 1.841445e-04, 8.053727e-06, 1.89...
$ ONOFFNET     <int> 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,...
$ PurpCode     <chr> " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",...
$ PurpDesc     <chr> " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",...
$ MeanDepth    <dbl> 0.09450471, 0.09872492, 0.28167548, NA, 0.56829879, 0.13899818, 0.55463734...
$ LakeVolume   <dbl> 1220.5177, 5407.7469, 49470.2953, NA, 39081.4758, 22468.7585, 75691.3313, ...
$ MaxDepth     <dbl> 0.23044897, 0.23288202, 0.63270356, NA, 1.09330535, 0.27875821, 1.26695295...
$ MeanDUsed    <dbl> 0.09450471, 0.09872492, 0.28167548, NA, 0.56829879, 0.13899818, 0.55463734...
$ MeanDCode    <chr> "4", "4", "4", NA, "4", "4", "4", "4", "4", "4", "4", NA, "4", "4", "4", "...
$ LakeArea     <dbl> 12914.89, 54775.91, 175628.68, NA, 68769.23, 161647.88, 136469.96, 187427....
$ Shape        <sf_geometry [degree]> MULTIPOLYGON (((-68.31665 4..., MULTIPOLYGON (((-68.3228 ...

Glimpse the NHDReachCrossReference table.

Observations: 5,856,425
Variables: 4
$ OldReachCode <fct> 01010003000640, 01010004001528, 01010004001679, 01010004001536, 0101000400...
$ OldReachDate <dttm> 1997-05-21, 1997-05-21, 1997-05-21, 1997-05-21, 1997-05-21, 1997-05-21, 1...
$ NewReachCode <fct> 01010003000737, 01010004001871, 01010004001873, 01010004001874, 0101000400...
$ NewReachDate <dttm> 1998-07-04, 1998-07-04, 1998-07-04, 1998-07-04, 1998-07-04, 1998-07-04, 1...

Filter

We can’t use the join method to connect to any NHDPlusV2 lakes that don’t have REACHCODE populated. We will revisit these lakes along with others that won’t connect later.

Convert

These data are already spatial polygons and we want a dataset with no geometry instead.

Select

nhd_plus <- nhd_plus_df %>%
  select(COMID, FDATE, GNIS_ID, GNIS_NAME, REACHCODE, AREASQKM)

Join LAGOS-US

This join creates many:many relationships. A scant few ReachCodes in the LAGOS-US population are associated with two Permanent_Identifiers before the join. Most reach codes don’t have an entry in the cross reference table, suggesting that lakes still holding their original reach code should have the same reach code in any version of the NHD.

346721 reach codes have only a new reach code in NHDReachCrossReference and the OldReachCode is missing. In other words, about 72.24% of LAGOS-US lakes have never changed reach codes. About a tenth of the lakes have no entry in NHDReachCrossReference, suggesting this table is usually but not always populated when new reach codes are assigned.

Numerous lakes aren’t able to be connected between the NHDPlusV2 and the NHD HR. The HR contains more small lakes, so let’s look for a minute only at lakes over 10 hectares. Here are a few examples of lakes where the old reach codes are unavailable or not the target reach code.

For those lakes that didn’t link between NHD versions, try linking them through GNIS IDs.

It works. 5316 lakes that couldn’t be linked with NHDReachCrossReference can be linked with the GNIS_ID value.

Select again

lagos_nhd_not_missing <- lagos_nhd_all %>%
  filter(!is.na(COMID))
lagos_nhd <- lagos_df %>%
  left_join(lagos_nhd_not_missing, by = "lagoslakeid") %>% # removes OldReachCodes that don't link but keeps all lakes
  left_join(nhd_gnis_nhd, by = "lagoslakeid") %>%
  mutate(NHDPlusv2_COMID = coalesce(COMID.x, COMID.y)) %>%
  mutate(NHDPlusv2_ReachCode = coalesce(OldReachCode, REACHCODE)) %>%
  mutate(NHDPlusv2_GNIS_Name = coalesce(GNIS_NAME.x, GNIS_NAME.y)) %>% #all-caps is medium res
  mutate(NHDPlusv2_AreaSqKm = coalesce(AREASQKM.x, AREASQKM.y)) %>%
  select(lagoslakeid, NHDPlusv2_COMID, NHDPlusv2_ReachCode, NHDPlusv2_GNIS_Name, NHDPlusv2_AreaSqKm)

LAGOS-NE

LAGOS-NE was the first release from the LAGOS project describing lakes in 17 states in the northeastern states. It is similar in most ways to LAGOS-US, but the NHD snapshots were taken several years ago. This dataset can be downloaded and unzipped from [https://portal.edirepository.org/nis/mapbrowse?packageid=edi.98.1].

When the LAGOS-US lagoslakeid values were generated, they were joined on Permanent_Identifier to the LAGOS-NE, so most of the lagoslakeid values should not have changed. Nonetheless, some could not be connected this way.

Import

Glimpse the original LAGOS-NE dataset.

Observations: 141,265
Variables: 35
$ ComID                <int> 145061933, 145050791, 145050750, 145050563, 142825415, 142825576, ...
$ Permanent_Identifier <fct> 145061933, 145050791, 145050750, 145050563, 142825415, 142825576, ...
$ FDate                <dttm> 2006-01-11 16:55:46, 2006-01-11 15:27:23, 2006-01-11 15:26:37, 20...
$ GNIS_ID              <dbl> NA, 4781, 4907, NA, NA, 5045, NA, 3906, NA, NA, NA, NA, 4214, NA, ...
$ GNIS_Name            <fct> NA, Lower Hudson Pond, Mink Marsh Pond, NA, NA, Mud Pond, NA, Deep...
$ AreaSqKm             <dbl> 0.039, 0.355, 0.073, 0.017, 0.021, 0.066, 0.018, 0.025, 0.014, 0.0...
$ Elevation            <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ ReachCode            <fct> 01010005000620, 01010004001847, 01010004001838, 01010004005842, 01...
$ FType                <int> 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 3...
$ FCode                <int> 39004, 39004, 39004, 39004, 39004, 39004, 39004, 39004, 39004, 390...
$ Lake_Area_Ha         <dbl> 3.888402, 35.450899, 7.317129, 1.684377, 2.088132, 6.614470, 1.817...
$ LakeConnectivity     <fct> DR_Stream, DR_LakeStream, DR_Stream, Headwater, Headwater, DR_Stre...
$ HU4_ZoneID           <fct> HU4_1, HU4_1, HU4_1, HU4_1, HU4_1, HU4_1, HU4_1, HU4_1, HU4_1, HU4...
$ HU4_Name             <fct> St. John, St. John, St. John, St. John, St. John, St. John, St. Jo...
$ HU6_ZoneID           <fct> HU6_1, HU6_1, HU6_1, HU6_1, HU6_1, HU6_1, HU6_1, HU6_1, HU6_1, HU6...
$ HU6_Name             <fct> St. John, St. John, St. John, St. John, St. John, St. John, St. Jo...
$ HU8_ZoneID           <fct> HU8_5, HU8_4, HU8_4, HU8_4, HU8_601, HU8_601, HU8_601, HU8_5, HU8_...
$ HU8_Name             <fct> Meduxnekeag, Aroostook, Aroostook, Aroostook, St. Francis River-Sa...
$ HU12_ZoneID          <fct> HU12_17971, HU12_17917, HU12_17915, HU12_17946, HU12_17762, HU12_1...
$ HU12_Name            <fct> South Branch Meduxnekeag River, Mooseleuk Lake, Bartlett Brook-Spr...
$ EDU_ZoneID           <fct> EDU_79, EDU_79, EDU_79, EDU_79, EDU_79, EDU_79, EDU_79, EDU_79, ED...
$ EDU_Name             <fct> Upper St. John - Aroostook, Upper St. John - Aroostook, Upper St. ...
$ COUNTY_ZoneID        <fct> County_303, County_312, County_312, County_303, County_303, County...
$ COUNTY_Name          <fct> Aroostook County, Piscataquis County, Piscataquis County, Aroostoo...
$ State_Name           <fct> Maine, Maine, Maine, Maine, Maine, Maine, Maine, Maine, Maine, Mai...
$ STATE_ZoneID         <fct> State_1, State_1, State_1, State_1, State_1, State_1, State_1, Sta...
$ Shape_Length         <dbl> 997.0809, 3626.5048, 2472.0295, 1602.0563, 1056.0734, 1325.3148, 8...
$ Shape_Area           <dbl> 38884.02, 354508.99, 73171.29, 16843.77, 20881.32, 66144.70, 18171...
$ HU4                  <fct> 0101, 0101, 0101, 0101, 0101, 0101, 0101, 0101, 0101, 0101, 0101, ...
$ HU6                  <fct> 010100, 010100, 010100, 010100, 010100, 010100, 010100, 010100, 01...
$ HU12                 <fct> 010100050102, 010100040303, 010100040301, 010100040904, 0101000804...
$ HU8                  <fct> 01010005, 01010004, 01010004, 01010004, 01010008, 01010008, 010100...
$ STATE                <fct> ME, ME, ME, ME, ME, ME, ME, ME, ME, ME, ME, ME, ME, ME, ME, ME, ME...
$ lagoslakeid          <int> 29903, 79876, 52999, 97563, 89329, 125499, 132198, 131140, 133209,...
$ Shape                <sf_geometry [m]> MULTIPOLYGON (((2148592 288..., MULTIPOLYGON (((204595...

Filter

No need to filter. These lakes had essentially the same criteria for inclusion as LAGO-US, above, except that they were confined to a 17-state region in the northeast U.S.

Convert and select

lagosNE <- lagosNE_orig %>%
  select(LAGOSNE_lagoslakeid = lagoslakeid, LAGOSNE_PermanentIdentifier = Permanent_Identifier, LAGOSNE_ReachCode = ReachCode, GNIS_ID, GNIS_Name) %>%
  st_set_geometry(NULL)

Join LAGOS-US

Unlike with NHDPlusV2, these two datasets shared the identifier Permanent_Identifier and we will try to join lakes on that column first. The subsequent two joins parallel the joins with NHDPlusV2, above. We will reuse the lagos_nhdx table.

After trying the code below (currently commented out), it seems upon further observation that the GNIS_ID values in LAGOS-NE have no useful relation to the latest GNIS_ID values.

Select again

lagosUS_lagosNE <- lagos_lagosNE_all %>%
  filter(!is.na(LAGOSNE_lagoslakeid)) %>%
  arrange(lagoslakeid)

NLA (US EPA National Lakes Assessment)

The lakes in the NLA are identified with their NHDPlus COMID and ReachCode. It should be simple to add them to the crosswalk by doing a 1:1 join with the NHDPlusV2 COMID.

Import

Import the two NLA files. It seems that the 2012 file already manages the link between the 2012 sites back to the 2007 sites.

Observations: 2,764
Variables: 111
$ SITE_ID          <chr> "NLA12_AL-101", "NLA12_AL-101", "NLA12_AL-102", "NLA12_AL-103", "NLA12...
$ VISIT_NO         <int> 1, 2, 1, 1, 1, 1, 2, NA, NA, NA, NA, NA, NA, 1, 1, 1, 1, 1, 1, 2, 1, 1...
$ UID              <int> 6300, 7374, 7228, 7292, 7368, 6267, 7394, NA, NA, NA, NA, NA, NA, 7375...
$ DATE_COL         <chr> "5/24/2012", "7/21/2012", "7/17/2012", "7/19/2012", "7/23/2012", "5/23...
$ AGGR_ECO3_2015   <chr> "EHIGH", "EHIGH", "EHIGH", "EHIGH", "PLNLOW", "PLNLOW", "PLNLOW", "PLN...
$ AGGR_ECO9_2015   <chr> "SAP", "SAP", "SAP", "SAP", "CPL", "CPL", "CPL", "CPL", "CPL", "SAP", ...
$ AREA_HA          <dbl> 1301.871970, 1301.871970, 72.950420, 10363.258480, 4731.474336, 32.561...
$ AREACLS          <chr> "F:500+", "F:500+", "D:50-100", "F:500+", "F:500+", "C:10-50", "C:10-5...
$ BORD_LAKE        <chr> "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No"...
$ CAT_UNIQUE       <chr> "NLA07RVT", "NLA07RVT", "NLA07RVT", "NLA07RVT", "NLA07RVT", "NLA12NEW"...
$ CH0712_CAT       <chr> "NLA07_RVT12", "NLA07_RVT12", "NLA07_RVT12", "NLA07_RVT12", "NLA07_RVT...
$ CH0712_USE       <chr> "Include", "Include", "Include", "Include", "Include", "Include", "Inc...
$ CH0712_WGT       <dbl> 20.288885, 20.288885, 46.617902, 51.331899, 101.491046, 83.376963, 83....
$ CNTYNAME         <chr> "TUSCALOOSA", "TUSCALOOSA", "CULLMAN", "TALLADEGA", "SUMTER", "WASHING...
$ COMID2007        <int> 21656744, 21656744, 18587568, 22273142, 21677972, 21639448, 21639448, ...
$ COMID2012        <int> 166759236, 166759236, 18587568, 166759059, 21677972, 21639448, 2163944...
$ COMIDS2007       <chr> "21656744", "21656744", "18587568", "22273142", "21677972", "21639448"...
$ DES_FTYPE        <chr> "Lake/Pond: Hydrographic Category = Perennial; Stage = Average Water E...
$ DSGN12           <chr> "Included", "Included", "Included", "Included", "Included", "Included"...
$ ELEVATION        <dbl> 57.03, 57.03, 247.04, 141.76, 22.28, 50.83, 50.83, 96.12, 77.74, 181.4...
$ EPA_REG          <chr> "Region_4", "Region_4", "Region_4", "Region_4", "Region_4", "Region_4"...
$ EVAL_NAME        <chr> "Holt Lock and Dam", "Holt Lock and Dam", "George Lake", "Logan Martin...
$ EVALSTAT         <chr> "TargetSampleable", "TargetSampleable", "TargetSampleable", "TargetSam...
$ FEOW_ID          <int> 153, 153, 153, 153, 153, 153, 153, 154, 153, 153, 154, 152, 155, 153, ...
$ FS_EW            <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ FW_ECO3          <chr> "EHIGH", "EHIGH", "EHIGH", "EHIGH", "PLNLOW", "PLNLOW", "PLNLOW", "PLN...
$ FW_ECO9          <chr> "SAP", "SAP", "SAP", "SAP", "CPL", "CPL", "CPL", "CPL", "CPL", "SAP", ...
$ GNIS_ID          <int> NA, NA, 131985, NA, NA, 117983, 117983, NA, 154123, NA, NA, NA, 133275...
$ GNIS_NAME        <chr> NA, NA, "George Lake", NA, NA, "Emmit Wood Lake", "Emmit Wood Lake", N...
$ HUC2             <int> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 11, 11, 8, 8, 11...
$ HUC8             <int> 3160112, 3160112, 3160109, 3150106, 3160201, 3160203, 3160203, 3140202...
$ LAKE_ORIGIN      <chr> "MAN_MADE", "MAN_MADE", "MAN_MADE", "MAN_MADE", "MAN_MADE", "MAN_MADE"...
$ LAKE_ORIGIN12    <chr> "RESERVOIR", "RESERVOIR", "RESERVOIR", "RESERVOIR", "RESERVOIR", "RESE...
$ LAT_DD83         <dbl> 33.29204, 33.29204, 34.22782, 33.76248, 32.51587, 31.62155, 31.62155, ...
$ LON_DD83         <dbl> -87.39138, -87.39138, -86.84345, -86.05316, -87.86108, -88.35374, -88....
$ MAJ_BASIN        <chr> "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "05_06", "3", "...
$ MDCATY           <chr> "NonREF07", "NonREF07", "NonREF07", "NonREF07", "NonREF07", "(20,50]",...
$ MISS_BASIN       <chr> "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "Yes...
$ NA_L1CODE        <int> 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8...
$ NA_L2CODE        <dbl> 8.4, 8.4, 8.4, 8.4, 8.3, 8.3, 8.3, 8.3, 8.3, 8.4, 8.3, 8.4, 8.3, 8.3, ...
$ NA_L3CODE        <chr> "8.4.9", "8.4.9", "8.4.9", "8.4.1", "8.3.5", "8.3.5", "8.3.5", "8.3.5"...
$ NARS_NAME        <chr> "Holt Lock and Dam", "Holt Lock and Dam", "George Lake", NA, NA, "Emmi...
$ NES_LAKE         <chr> "NESLake", "NESLake", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...
$ NESLAKE_ID       <chr> "105", "105", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...
$ NESSTORET        <chr> "105", "105", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...
$ OWN_TYPE         <chr> "Non Federal", "Non Federal", "Non Federal", "Non Federal", "Non Feder...
$ OWNSHP           <chr> "Non-Federal", "Non-Federal", "Non-Federal", "Non-Federal", "Non-Feder...
$ PANEL            <chr> "NLA07RVT2", "NLA07RVT2", "NLA07RVT", "NLA07RVT", "NLA07RVT", "NLA12RV...
$ PERIM_KM         <dbl> 104.2086662, 104.2086662, 11.8723053, 688.4591342, 698.1088203, 2.9989...
$ RCHCODE          <chr> "3.16011E+12", "3.16011E+12", "3.16011E+12", "3.15011E+12", "3.16011E+...
$ RT_NLA12         <chr> "T", "T", "S", "S", "S", "S", "S", NA, NA, NA, NA, NA, NA, "R", "S", "...
$ SITEID_07        <chr> "NLA06608-2187", "NLA06608-2187", "NLA06608-0459", "NLA06608-2955", "N...
$ SITESAMP         <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "N", "N", "N", "N", "N", "N", "Y", ...
$ SITETYPE         <chr> "PROB", "PROB", "PROB", "PROB", "PROB", "PROB", "PROB", "PROB", "PROB"...
$ SIZE_CLASS       <chr> ">50", ">50", ">50", ">50", ">50", "(20,50]", "(20,50]", "(1,4]", "(10...
$ ST_DSGN          <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ ST_MDCATY        <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ ST_PANEL         <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ ST_SITEID        <chr> "NLA12_AL-101", "NLA12_AL-101", "NLA12_AL-102", "NLA12_AL-103", "NLA12...
$ ST_STRATUM       <chr> "AL_NLA07RVT", "AL_NLA07RVT", "AL_NLA07RVT", "AL_NLA07RVT", "AL_NLA07R...
$ ST_WGT_ALL       <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
$ ST_WGT_CAT       <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ ST_WGT_DSGN      <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
$ STATE            <chr> "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL"...
$ STATE_NLA        <chr> "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL"...
$ STATE_PCNT       <int> 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, ...
$ STATECTY         <int> 1073, 1073, 1043, 1055, 1063, 1129, 1129, 1031, 1085, 1009, 1053, 1071...
$ STATUS           <chr> "Target_Sampled", "Target_Sampled", "Target_Sampled", "Target_Sampled"...
$ STATUS_ST        <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ STRATUM          <chr> "AL_NLA07RVT", "AL_NLA07RVT", "AL_NLA07RVT", "AL_NLA07RVT", "AL_NLA07R...
$ TNT              <chr> "Target", "Target", "Target", "Target", "Target", "Target", "Target", ...
$ TNT_ST           <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ URBAN            <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "No", "No", "No", "No", "No", "No",...
$ US_L3CODE        <int> 68, 68, 68, 67, 65, 65, 65, 65, 65, 68, 65, 68, 65, 65, 65, 67, 45, 65...
$ US_L3CODE_2015   <int> 68, 68, 68, 67, 65, 65, 65, 65, 65, 68, 65, 68, 65, 65, 65, 67, 45, 65...
$ US_L4CODE        <chr> "68f", "68f", "68d", "67g", "65b", "65f", "65f", "65d", "65a", "68d", ...
$ US_L4CODE_2015   <chr> "68f", "68f", "68d", "67g", "65p", "65f", "65f", "65d", "65a", "68d", ...
$ WGT_ALL          <dbl> 20.288885, 20.288885, 46.617902, 51.331899, 101.491046, 83.376963, 83....
$ WGT_CAT          <chr> "AL_>4", "AL_>4", "AL_>4", "AL_>4", "AL_>4", "AL_>4", "AL_>4", "AL_(1,...
$ WGT_DSGN         <dbl> 3.666670, 3.666670, 3.666667, 3.666667, 3.666667, 21.875000, 21.875000...
$ XCOORD           <dbl> 795432.2, 795432.2, 835851.3, 913172.8, 759549.6, 721685.4, 721685.4, ...
$ YCOORD           <dbl> -434840.8, -434840.8, -326047.1, -370517.5, -524957.0, -628108.3, -628...
$ ECO_BIO          <chr> "EHIGH", "EHIGH", "EHIGH", "EHIGH", "CPL", "CPL", "CPL", "CPL", "CPL",...
$ IM_COMMENT       <chr> "No phab done on this visit; visit 2 assigned as index visit", "Assign...
$ INDEX_NLA        <chr> "N", "Y", "Y", "Y", "Y", "N", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", ...
$ INDXSAMP_BENT    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ INDXSAMP_CHEM    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ INDXSAMP_CHLA    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ INDXSAMP_CORE    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ INDXSAMP_ENTE    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ INDXSAMP_MICR    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ INDXSAMP_PHAB    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ INDXSAMP_SDHG    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ INDXSAMP_ZOOP    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ REF_NLA12_NUTR   <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "R", NA, NA, "R", ...
$ RT_NLA12_BENT    <chr> "T", "T", "S", "S", "S", "S", "S", NA, NA, NA, NA, NA, NA, "R", "S", "...
$ RT_NLA12_ZOOP    <chr> "T", "T", "S", "S", "S", "S", "S", NA, NA, NA, NA, NA, NA, "R", "S", "...
$ SAMPLED_BENT     <chr> "Y", "Y", "Y", "N", "Y", "Y", "Y", NA, NA, NA, NA, NA, NA, "Y", "Y", "...
$ SAMPLED_CORE     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ SAMPLED_ENTE     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ SAMPLED_MICR     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ SAMPLED_PHAB     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ SAMPLED_PHYT     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ SAMPLED_PROFILE  <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ SAMPLED_SDHG     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ SAMPLED_ZOCN     <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", NA, NA, NA, NA, NA, NA, "Y", "Y", "...
$ SAMPLED_ZOCR     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ SAMPLED_ZOFN     <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", NA, NA, NA, NA, NA, NA, "Y", "Y", "...
$ SAMPLED_ZOFR     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ SAMPLED_ZOOP     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ PUBLICATION_DATE <chr> "8/23/2016", "8/23/2016", "8/23/2016", "8/23/2016", "8/23/2016", "8/23...

Unfortunately, the RCHCODE values in the 2012 data that can be downloaded online were exported improperly, using scientific notation that cuts off the very important final digits. For example:

With luck, we can work around this issue.

Filter

No need.

Convert

No need.

Select

nla2007 <- nla2007_orig %>%
  distinct(SITE_ID, REACHCODE, COM_ID)
nla2012 <- nla2012_orig %>%
  distinct(SITE_ID, SITEID_07, COMID2012, COMID2007, COMIDS2007, GNIS_ID, GNIS_NAME, NESSTORET)

Join to LAGOS_US via NHDPlusV2 via the V1-to-V2 crosswalk.

We will use the nla2012 table as the left table in the join and also join through the original nhd_plus dataset so that we can produce a list of NLA lakes that could not be linked to a lagoslakeid. The NLA lakes that don’t link will be assigned a lagoslakeid through our manual linking process (that starts with a spatial link).

Check on how many lakes didn’t link through each step.

37 lakes out of 2664 NLA lakes cannot be linked to the NHDPlusV2. We did try the V1-to-V2 crosswalk and were not able to make any additional links. Far more lakes are unable to be linked to a lagoslakeid: 711. This is due to the poor match between the NHDPlusV2 and the LAGOS Lake population. If we improve that link, these numbers will increase. This work is proposed.

Select again

Select 2 columns from the NLA 2012 and lagoslakeid.

nla2012_lagos <- nla2012_lagos_join %>%
  select(
    NLA2012_SITE_ID = SITE_ID,
    NLA2007_SITE_ID = SITEID_07,
    lagoslakeid
  )

Final, single crosswalk table

For the final table, we’ll join all the previous results together with the entire LAGOS-US lake population on the left side of the join. Then, in order to facilitate a user understanding of 1-to-many relationships in the table, we will generate some count columns that indicate when multiple identifiers in one dataset relate to a single identifier in another. Finally, we will do the final selection of columns for the output and rename a few more columns to match the naming template.

Glimpse at the final table.

Observations: 569,329
Variables: 26
$ lagoslakeid                      <int> 31198, 31198, 31198, 31198, 31198, 31198, 122, 122, 12...
$ NHDHR_PermanentIdentifier        <chr> "120020498", "120020498", "120020498", "120020498", "1...
$ NHDHR_ReachCode                  <chr> "04010201003330", "04010201003330", "04010201003330", ...
$ NHDHR_AreaSqKm                   <dbl> 2.745000, 2.745000, 2.745000, 2.745000, 2.745000, 2.74...
$ GNIS_ID                          <int> 649289, 649289, 649289, 649289, 649289, 649289, 653169...
$ GNIS_Name                        <chr> "Perch Lake", "Perch Lake", "Perch Lake", "Perch Lake"...
$ LAGOS_LakeName                   <chr> "Perch Lake", "Perch Lake", "Perch Lake", "Perch Lake"...
$ LAGOS_CountyName                 <chr> "Carlton County", "Carlton County", "Carlton County", ...
$ LAGOS_CountyFIPS                 <chr> "27017", "27017", "27017", "27017", "27017", "27017", ...
$ LAGOS_LatitudeNAD83              <dbl> 46.68943, 46.68943, 46.68943, 46.68943, 46.68943, 46.6...
$ LAGOS_LongitudeNAD83             <dbl> -92.67066, -92.67066, -92.67066, -92.67066, -92.67066,...
$ State                            <chr> "MN", "MN", "MN", "MN", "MN", "MN", "MN", "MN", "MN", ...
$ WQP_MonitoringLocationIdentifier <chr> "FONDULAC-114A", "FONDULAC-114B", "FONDULAC_WQX-114A",...
$ WQP_MonitoringLocationName       <chr> "Perch Lake (North Basin)", "Perch Lake (South Basin)"...
$ WQP_ProviderName                 <chr> "STORET", "STORET", "STORET", "STORET", "STORET", "STO...
$ NHDPlusv2_COMID                  <int> 1776072, 1776072, 1776072, 1776072, 1776072, 1776072, ...
$ NHDPlusv2_ReachCode              <chr> "04010201003330", "04010201003330", "04010201003330", ...
$ NHDPlusv2_AreaSqKm               <dbl> 2.720, 2.720, 2.720, 2.720, 2.720, 2.720, 1.348, 1.348...
$ LAGOSNE_lagoslakeid              <int> 31198, 31198, 31198, 31198, 31198, 31198, 122, 122, 12...
$ NLA2007_SITE_ID                  <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ NLA2012_SITE_ID                  <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ count_wqp_per_lagos_id           <int> 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 4, 4, ...
$ count_nhdplusv2_per_lagos_id     <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 1, 2, 2, ...
$ count_lagos_per_nhdplusv2_id     <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, NA, 1, 1, 1,...
$ count_lagosNE_per_lagos_id       <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ count_lagos_per_lagosNE_id       <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...

An example of a group of lakes in the final table.

Write out the final product.

List of to-dos and ideas to make more or better connections

  1. PROBLEM: Almost 25% of lakes cannot be linked to their NHDPlusv2 identifier (and therefore their StreamCat/LakeCat identifier). SOLUTION: Link differing NHD version lakes through spatial analysis. This is the highest impact suggestion.
  2. PROBLEM: There are still many unlinked WQP sites and some of them do link easily if adequate rules are proposed, but introduce a higher possibility of creating incorrect links for other similar sites. SOLUTION: We could make more links to WQP sites if we added a way to indicate “low confidence” links. For instance: we could add more sites that are within 100 m but have no name match.
  3. PROBLEM: Some applications ask users to specify the lake they’re at when the user does not have GPS (Ewing and others harmful algal bloom app). SOLUTION: Add “nearest municipality” using TIGER data and a “closest” spatial join. (Discussed previously with Holly Ewing and was identified as desirable at this time, but cut from this draft for time.)
  4. Manual links for LAGOS-NE lakes that have limno data (26 lakes) but that can’t be found through the Permanent_Identifier or reach code in LAGOS-US. (In progress)
  5. Manual links for any NLA sites that still don’t connect if we add the spatial analysis in TO-DO item (B).
  6. Merge NHDPlusV2 names into the semi-colon list (cut for time–needs another join/distinct/verbose name calculation chunk)

Things that can’t be done with the crosswalk

These items can be described as designed limitations because this lake identifier crosswalk is designed primarily to work with LAGOS. Or–if there is enough interest from the preview group–we can consider adding these capabilities. G) A user cannot find identifiers pertaining to a lake that isn’t in LAGOS-US. SOLUTION: Use outer joins and allow the crosswalk to grow a fair amount in size to allow NULLs in any of the identifiers. Revise the documentation to reflect the expansion. H) A user cannot connect WQP sites to the NHDPlusV2 representation of lakes. Example: 2 NHDPlusV2 lakes to 1 LAGOS-US lake. SOLUTION: Refine the entity-relationship model to join between the WQP and NHDPlusV2 directly. Rework subsequent joins in the script to accomodate the change. This change probably won’t affect the overall size or usability of the crosswalk too much.

Proposed ER Diagram demonstrating change “A” and “H” above

Proposed entity-relationship diagram showing two additions, in color

Proposed entity-relationship diagram showing two additions, in color

LS0tDQp0aXRsZTogJ0xBR09TIExha2UgTGluazogQ3JlYXRpb24nDQphbHdheXNfYWxsb3dfaHRtbDogeWVzDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShzZikNCmxpYnJhcnkoZGF0YVJldHJpZXZhbCkgIyBXUVAgd2ViIHNlcnZpY2UgbGlicmFyeQ0KbGlicmFyeShYTUwpDQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KG1hcHZpZXcpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UpDQoNCk5BRDgzID0gJytpbml0PWVwc2c6NDI2OScNCk5BRDI3ID0gJytpbml0PWVwc2c6NDI2NycNCldHUzg0ID0gJytpbml0PWVwc2c6NDMyNicNCldHUzcyID0gJytpbml0PWVwc2c6NDMyMicNCkFMQkVSU19VU0dTID0gJytwcm9qPWFlYSArbGF0XzE9MjkuNSArbGF0XzI9NDUuNSArbGF0XzA9MjMgK2xvbl8wPS05NiAreF8wPTAgK3lfMD0wICtkYXR1bT1OQUQ4MyArdW5pdHM9bSArbm9fZGVmcycNClVTR1NfQVRUUiA8LSBwYXN0ZTAoIjxhIGhyZWY9J2h0dHBzOi8vd3d3LnVzZ3MuZ292Lyc+IiwNCiAgICAgICAgICAgICAgIlUuUy4gR2VvbG9naWNhbCBTdXJ2ZXk8L2E+IHwgIiwNCiAgICAgICAgICAgICAgIjxhIGhyZWY9J2h0dHBzOi8vd3d3LnVzZ3MuZ292L2xhd3MvcG9saWNpZXNfbm90aWNlcy5odG1sJz4iLA0KICAgICAgICAgICAgICAiUG9saWNpZXM8L2E+IikNCk5IRF9VUkwgPC0gJ2h0dHBzOi8vaHlkcm8ubmF0aW9uYWxtYXAuZ292L2FyY2dpcy9zZXJ2aWNlcy9uaGQvTWFwU2VydmVyL1dNU1NlcnZlcicNCg0KbGlzdF9zaGFyZWRfd29yZHMgPC0gZnVuY3Rpb24oc3RyaW5nMSwgc3RyaW5nMiwgZXhjbHVkZV9sYWtlX3dvcmRzID0gVFJVRSkgew0KICBleGNsdXNpb25fc2V0IDwtIGMoJ0xBS0UnLCAnUE9ORCcsICdSRVNFUlZPSVInLCAnREFNJykNCiAgd29yZHMxIDwtIHN0cmluZzEgJT4lDQogICAgdG91cHBlcigpICU+JQ0KICAgIHN0cnNwbGl0KCJcXHMrIikNCiAgd29yZHMyIDwtIHN0cmluZzIgJT4lDQogICAgdG91cHBlcigpICU+JQ0KICAgIHN0cnNwbGl0KCJcXHMrIikNCiAgaWYgKGV4Y2x1ZGVfbGFrZV93b3JkcyA9PSBUUlVFKSB7DQogICAgd29yZHMxIDwtIHNhcHBseSh3b3JkczEsIGZ1bmN0aW9uKHgpIHNldGRpZmYoeCwgZXhjbHVzaW9uX3NldCkpDQogICAgd29yZHMyIDwtIHNhcHBseSh3b3JkczIsIGZ1bmN0aW9uKHgpIHNldGRpZmYoeCwgZXhjbHVzaW9uX3NldCkpDQogIH0NCiAgaW50ZXJzZWN0aW9uIDwtIG1hcHBseShpbnRlcnNlY3QsIHdvcmRzMSwgd29yZHMyLCBVU0UuTkFNRVMgPSBGQUxTRSkNCiAgDQogIGZvcm1hdF9yZXN1bHQgPC0gZnVuY3Rpb24oeCkgew0KICAgIGlmIChsZW5ndGgoeCkgPiAxKSB7DQogICAgICByZXN1bHQgPC0gcGFzdGUoeCwgY29sbGFwc2UgPSAiOyAiKQ0KICAgIH0NCiAgICBlbHNlIHsNCiAgICAgIGlmIChpZGVudGljYWwoeCwgY2hhcmFjdGVyKDApKSkgew0KICAgICAgICByZXN1bHQgPC0gYXMuY2hhcmFjdGVyKE5BKQ0KICAgICAgfQ0KICAgICAgZWxzZSB7DQogICAgICAgIGlmIChpcy5uYSh4KSkgew0KICAgICAgICAgIHJlc3VsdCA8LSBhcy5jaGFyYWN0ZXIoTkEpDQogICAgICAgIH0NCiAgICAgICAgZWxzZSB7DQogICAgICAgICAgcmVzdWx0IDwtIHBhc3RlKHgsIGNvbGxhcHNlID0gIjsgIikNCiAgICAgICAgfQ0KICAgICAgfQ0KICAgIH0NCiAgfQ0KICANCiAgcmVzdWx0IDwtIHNhcHBseShpbnRlcnNlY3Rpb24sIGZvcm1hdF9yZXN1bHQpDQogIHJldHVybihyZXN1bHQpDQp9DQpgYGANClRoZSBwdXJwb3NlIG9mIHRoaXMgZG9jdW1lbnQgaXMgdG8gZGVsaW5lYXRlIHRoZSBwcm9jZXNzaW5nIHN0ZXBzIHVzZWQgdG8gam9pbiBsYWtlIGlkZW50aWZpZXJzIGZyb20gNSBkYXRhIHByb2R1Y3RzIGludG8gYSBzaW5nbGUgbGFrZSBpZGVudGlmaWVyIHRhYmxlIGNhbGxlZCBMQUdPUyBMYWtlIExpbmsgKCoqd29ya2luZyBuYW1lKiopLg0KDQojIERlZmluaXRpb25zIGluIHRoaXMgZG9jdW1lbnQNCiJMYWtlIjogUGVybWFuZW50IGxha2Ugb3IgcmVzZXJ2b2lyLg0KDQojIFdoYXQgaXMgTEFHT1MgTGFrZSBMaW5rPw0KTEFHT1MgTGFrZSBMaW5rIGlzIGEgdGFidWxhciBkYXRhc2V0IChhIGNyb3Nzd2FsayB0YWJsZSkgdGhhdCBjYW4gYmUgdXNlZCB0byBjb25uZWN0IG9uZSBsYWtlLXJlbGF0ZWQgZGF0YXNldCB0byBhbm90aGVyIGZvciBtYW55IGNvbW1vbiBsYWtlIGRhdGFzZXRzLiBTZXZlcmFsIGxha2UgZGF0YXNldHMgYXJlIGluIGNvbW1vbiB1c2Ugb24gdGhlaXIgb3duIG9yIGFzIGEgYmFzZSBmb3Igc2NpZW50aWZpYyBkYXRhIHByb2R1Y3RzIGFuZCBMQUdPUyBMYWtlIExpbmsgaXMgaW50ZW5kZWQgdG8gbWFrZSBpdCBlYXNpZXIgdG8gY29tYmluZSBsYWtlLXJlbGF0ZWQgZGF0YSBiZXR3ZWVuIG11bHRpcGxlIHNvdXJjZXMuIFRoZSB0YWJsZSBjYW4gYmUgc2VhcmNoZWQgdG8gZmluZCBpZGVudGlmaWVycyBhbmQgbG9jYXRpb24gZm9yIGEgcGFydGljdWxhciBsYWtlLCBvciBpdCBjYW4gYmUgdXNlZCBpbiBkYXRhIGpvaW4gb3BlcmF0aW9ucyB0byBjb252ZXJ0IGlkZW50aWZpZXJzIGVuIG1hc3NlLiANCg0KVGhlcmUgYXJlIHR3byBtYWluIHNwYXRpYWwgcmVwcmVzZW50YXRpb25zIHVzZWQgZm9yIGxha2UgbG9jYXRpb25zOiBwb2x5Z29ucywgdXNlZCBpbiB0aGUgdmFyaW91cyBOSEQgcHJvZHVjdHMgKE5hdGlvbmFsIEh5ZHJvZ3JhcGh5IERhdGFzZXQpLCBhbmQgcG9pbnRzLCB1c2VkIGluIG90aGVyIG5hdGlvbmFsIGRhdGFzZXRzLiBJbiBhZGRpdGlvbiB0byB0aGUgc3BhdGlhbCByZXByZXNlbnRhdGlvbnMsIHRoZXJlIGFyZSBhIHZhcmlldHkgb2YgaWRlbnRpZmllcnMgZm91bmQgYW1vbmcgdGhlIGRhdGFzZXRzIHBvcnRyYXlpbmcgbGFrZXMgaW4gdGhlIFVuaXRlZCBTdGF0ZXM6IHN0YXRlIGFnZW5jeSBJRHMsIFdhdGVyIFF1YWxpdHkgUG9ydGFsIE1vbml0b3JpbmdMb2NhdGlvbklkZW50aWZpZXIgKGZyb20gc3lzdGVtcyBzdWNoIGFzIFNUT1JFVCBhbmQgTldJUyksIE5IRFBsdXNWMiBDT01JRCwgTkhEIFJlYWNoQ29kZSwgTkhELUhSIFBlcm1hbmVudF9JZGVudGlmaWVyLCBHTklTX0lELiBGaW5hbGx5LCBsYWtlcyBhcmUgc29tZXRpbWVzIG5hbWVkIGFuZCBjYW4gYmUgaWRlbnRpZmllZCBieSB0aGVpciBuYW1lIGFsb25lIGlmIGl0IHVuaXF1ZSwgb3IgdGhlaXIgbmFtZSBhbmQgZ2VvZ3JhcGhpYyBjb250ZXh0Lg0KDQpUaGVyZSBhcmUgc2V2ZXJhbCBvYnN0YWNsZXMgdG8gcmVsaWFibHkgaWRlbnRpZnlpbmcgY29tbW9uIGxha2VzIGJldHdlZW4gdGhlc2UgZGF0YXNldHM6IA0KDQoqIEluYWRlcXVhdGUgbG9jYXRpb24gYWNjdXJhY3kNCiogSW5jb25zaXN0ZW50IGNsYXNzaWZpY2F0aW9uIG9mIHdhdGVyYm9kaWVzIGFzIGxha2VzIHZzLiBhbm90aGVyIHR5cGUNCiogSW5jb25zaXN0ZW50IGRlbGluZWF0aW9uIG9mIGxha2UgZXh0ZW50DQoqIENvbmZsaWN0aW5nIG5hbWVzDQoqIFVuYWNjb3VudGVkIGNoYW5nZSBpbiBpZGVudGlmaWVycyB3aXRoaW4gYSBkYXRhc2V0DQoqIFVuc3luY2hyb25pemVkIHVwZGF0ZSBwYXR0ZXJucyBiZXR3ZWVuIGRhdGFzZXRzIA0KDQpXaGVuIEkgc2F5ICJpbmFkZXF1YXRlIiBvciAiaW5jb25zaXN0ZW50IiBoZXJlLCBJIGFtIGRlc2NyaWJpbmcgdGhlIHF1YWxpdHkgcmVsYXRpdmUgdG8gbXkgc3BlY2lmaWMgdGFzayBvZiBjb25uZWN0aW5nIGRhdGFzZXRzLiBJbmRlcGVuZGVudGx5LCB0aGVzZSBkYXRhc2V0cyBoYXZlIGhpZ2ggc3RhbmRhcmRzIGZvciBkYXRhIHF1YWxpdHktLWJ1dCB0d28gZGF0YXNldHMgbWF5IHVzZSwgZm9yIGV4YW1wbGUsIGRpZmZlcmVudCBkZWZpbml0aW9ucyBvZiB0aGUgbGFrZSBlbnRpdHksIGFuZCB0aGF0IGlzIHdoZXJlIHByb2JsZW1zIGFyaXNlIGZvciBteSB0YXNrLg0KDQojIEVudGl0eS1yZWxhdGlvbnNoaXAgZGlhZ3JhbQ0KDQohWypFbnRpdHktcmVsYXRpb25zaGlwIGRpYWdyYW0qXSguL2ltYWdlcy9FUkRfYXNfaXMuUE5HKQ0KDQojIERhdGEgUHJvY2Vzc2luZyBQaXBlbGluZQ0KNSBtYWluIGRhdGFzZXRzIHdpbGwgYmUgaW50cm9kdWNlZCB0byBjcmVhdGUgdGhlIGNyb3Nzd2FsazogTEFHT1MgKFVTKSwgR05JUywgV1FQLCBOSERQbHVzVjIgKG1lZGl1bS1yZXNvbHV0aW9uKSwgYW5kIExBR09TLU5FLiBGb3IgZWFjaCBkYXRhc2V0LCB0aGUgd29ya2Zsb3cgaXMgYXMgZm9sbG93czogDQoNCjEpICoqSW1wb3J0LioqIE1vZGlmeSBmaWVsZHMgYW5kIHByZXBhcmUgdGhlIGRhdGEgZnJhbWUgZm9yIGxhdGVyIHdvcmsuDQoyKSAqKkZpbHRlci4qKiBXZSBmb2N1cyBoZXJlIG9uIGxha2VzIGFuZCByZXNlcnZvaXJzIGluIHRoZSBjb250aW5lbnRhbCBVbml0ZWQgU3RhdGVzLiBJbiBvcmRlciB0byBwcmVzZXJ2ZSB0aGlzIGZvY3VzLCBjYXRlZ29yaWVzIG9mIGVudGl0aWVzIHRoYXQgYXJlIGxlc3MgbGlrZWx5IHRvIHJlcHJlc2VudCBvbmUgb2YgdGhlc2UgZmVhdHVyZXMgYXJlIHBydW5lZCBhd2F5IGR1cmluZyB0aGlzIHN0ZXAsIGV2ZW4gaWYgdGhvc2UgY2F0ZWdvcmllcyBzb21ldGltZXMgY29ubmVjdCB0byBhIExBR09TLVVTIGxha2UuIFRoZSBjcm9zc3dhbGsgb25seSBpbmNsdWRlcyByZWxhdGlvbnNoaXBzIGlmIHRoZXkgdWx0aW1hdGVseSBjb25uZWN0IGJhY2sgdG8gYSBMQUdPUy1VUyBsYWtlLiBGb3IgZXhhbXBsZS0tZXZlbiB0aG91Z2ggeW91IGNhbiB1c2UgdGhpcyB0YWJsZSB0byB3YWxrIGJldHdlZW4gV1FQIHNpdGVzIGFuZCBOSERQbHVzVjIgbGFrZXMsIHRoZSByZWxhdGlvbnNoaXAgaXMgbm90IGNvbXByZWhlbnNpdmUgYmVjYXVzZSBsYWtlcyBub3QgZm91bmQgaW4gTEFHT1MtVVMgYXJlIG1pc3NpbmcuDQozKSAqKkNvbnZlcnQqKiBiZXR3ZWVuIHNwYXRpYWwgYW5kIG5vbi1zcGF0aWFsIGRhdGEgZm9ybWF0cywgYXMgbmVlZGVkLiBTcGF0aWFsIGZvcm1hdHMgYXJlIHByb2plY3RlZCB0byB0aGUgVVNHUyBBbGJlcnMgQ29uaWMgRXF1YWwgQXJlYSBwcm9qZWN0aW9uIGZvciBjb25zaXN0ZW5jeS4NCjQpICoqU2VsZWN0Kiogb25seSB0aGUgbmVjZXNzYXJ5IGNvbHVtbnMgZm9yIHRoZSB1cGNvbWluZyB3b3JrLg0KNSkgKipKb2luIExBR09TLVVTKiogdG8gZWFjaCBvdGhlciBkYXRhc2V0LCBpbmRpdmlkdWFsbHkuIFRoaXMgc3RlcCBtYXkgaW5jbHVkZSBzcGF0aWFsIGpvaW5zLCBqb2lucyBvbiBjb21tb24gaWRlbnRpZmllcnMuIEFmdGVyIGpvaW5pbmcsIGlkZW50aWZ5aW5nIGZpZWxkcyBtYXkgYmUgZmxhdHRlbmVkIGludG8gYSBzaW5nbGUgY29uY2F0ZW5hdGVkIGZpZWxkIG9yIGNvYWxlc2NlZC4NCjYpICoqU2VsZWN0IGFnYWluKiogYWdhaW4gYXMgbmVlZGVkIGJlZm9yZSB0aGUgZmluYWwgam9pbi4NCg0KIVsqUHJvY2Vzc2luZyBQaXBlbGluZSpdKC4vaW1hZ2VzL1Byb2Nlc3NpbmdfZmxvdy5QTkcpDQoNCkZpbmFsbHksIHRoZSByZXN1bHRzIG9mIHRoZSBtdWx0aXBsZSBqb2lucyBpbiBzdGVwIDQgd2lsbCBiZSBtZXJnZWQgaW50byBhIHNpbmdsZSBjcm9zc3dhbGsgdGFibGUgd2l0aCBvbmx5IHRoZSBuZWNlc3NhcnkgZmllbGRzIHJlbWFpbmluZy4NCg0KIyBMQUdPUy1VUw0KVGhlIExBR09TLVVTIGxha2UgcG9wdWxhdGlvbiBpcyB0aGUgZm9jYWwgZGF0YXNldCBvZiB0aGUgTEFHT1MgTGFrZSBMaW5rIGNyb3Nzd2FsayAodG9wIGNlbnRlciwgRmlndXJlIFxyZWZ7ZmlnOmZpZ3N9KS4gV2Ugd2lsbCBjb25uZWN0IGFsbCBvdGhlciBkYXRhc2V0cyB0byB0aGlzIG9uZSBpbiB0aGUgY3Jvc3N3YWxrLiBMYWtlcyB3aWxsIG9ubHkgVGhpcyBkYXRhc2V0IGlzIGEgc3Vic2V0IG9mIHRoZSBOSEQgSGlnaCBSZXNvbHV0aW9uIE5IRFdhdGVyYm9keSBsYXllcnMgKHNlZSAiRmlsdGVyIiBzZWN0aW9uIGZvciBkZXRhaWxzKSByZXByZXNlbnRpbmcgcGVybWFuZW50LCBub24tYXJ0aWZpY2lhbCBMYWtlUG9uZCBhbmQgUmVzZXJ2b2lyIHdhdGVyYm9kaWVzLiBDdXJyZW50bHksIExBR09TLVVTIGlzIHVuZGVyIGRldmVsb3BtZW50IGFuZCB3aGlsZSB0aGUgbGFrZSBwb2x5Z29uIGRhdGFzZXQgaXMgY29tcGxldGVkLCBtdWNoIG9mIHRoZSBkYXRhYmFzZSByZW1haW5zIHRvIGJlIGJ1aWx0IGluIDIwMTggYW5kIDIwMTkuDQoNClRoZSBwcmltYXJ5IGlkZW50aWZpZXIgZm9yIGxha2VzIGluIHRoaXMgZGF0YXNldCBpcyAqKmxhZ29zbGFrZWlkKiouIEEgc2Vjb25kYXJ5IHVuaXF1ZSBpZGVudGlmaWVyIGlzIG5hbWVkICoqbmhkaWQqKiBpbiB0aGUgImxvY3VzIiB0YWJsZSwgd2hpY2ggY29ycmVzcG9uZHMgdG8gdGhlICoqUGVybWFuZW50X0lkZW50aWZpZXIqKiBpbiB0aGUgTkhEIGFuZCBpbiB0aGUgR0lTIGxheWVyIGltcG9ydGVkIGhlcmUuDQoNCiMjIEltcG9ydA0KV2UnbGwgaW1wb3J0IHRoZSBHSVMgcG9seWdvbiBsYXllciBwcmVwYXJlZCBmb3IgTEFHT1MtVVMuIEdsaW1wc2UgdGhlIHBvbHlnb24gbGF5ZXI6DQpgYGB7ciByZWFkLWxhZ29zfQ0KIyBsYWdvc19zZiA8LSBzdF9yZWFkKCdEOi9Db250aW5lbnRhbF9MaW1ub2xvZ3kvRGF0YV9Xb3JraW5nL0xBR09TX1VTX1ByZWRlY2Vzc29ycy5nZGInLCAnTkhEV2F0ZXJib2R5X0xBR09TJywgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSAlPiUNCiMgICBzdF96bShkcm9wPVRSVUUpICU+JQ0KIyAgIG11dGF0ZShHTklTX0lEID0gYXMuaW50ZWdlcihHTklTX0lEKSkgJT4lDQojICAgc3RfdHJhbnNmb3JtKEFMQkVSU19VU0dTKSAjIG5vIGFjdHVhbCBjaGFuZ2UsIGp1c3QgcHJvajRzdHJpbmcgaG91c2VrZWVwaW5nLg0KIyBzYXZlKGxhZ29zX3NmLCBmaWxlID0gJy4vcmRhdGEvbGFnb3Nfc2YuUkRhdGEnKQ0KbG9hZCgnLi9yZGF0YS9sYWdvc19zZi5SRGF0YScpDQpnbGltcHNlKGxhZ29zX3NmLCB3aWR0aCA9IDEwMCkNCmBgYA0KDQojIyBGaWx0ZXINClRoZSBMQUdPUy1VUyBkYXRhc2V0IGhhcyBhbHJlYWR5IGJlZW4gZmlsdGVyZWQgZnJvbSB0aGUgc291cmNlIGRhdGFzZXQgb2YgYWxsIE5IRFdhdGVyYm9keSBmZWF0dXJlcyB0byBnZW5lcmF0ZSB0aGUgZmluYWwgdGFyZ2V0IGxha2UgcG9wdWxhdGlvbi4gVGhlIGNvZGUgaXMgbm90IGluY2x1ZGVkIGJ1dCB0aGUgcHJvY2Vzc2luZyBydWxlcyBhcmUgc3VtbWFyaXplZCBiZWxvdy4NCg0KQ3JpdGVyaWEgZm9yIHNlbGVjdGluZyBOSEQgbGFrZSBwb2x5Z29ucyBmb3IgaW5jbHVzaW9uIGluIExBR09TLVVTIHdlcmUgYXMgZm9sbG93cy4gSW5jbHVkZWQgbGFrZXMgbXVzdDoNCg0KKiBCZSBkZXJpdmVkIGZyb20gc25hcHNob3RzIG9mIHRoZSBOSEQgc3RhZ2VkIGJ5IHN1YnJlZ2lvbiB0YWtlbiAyMDE2LTEyLTE1LCAyMDE2LTEyLTE2LCAyMDE3LTAxLTAzIChIVUM0IDEwMTkpLCAyMDE3LTAxLTAzIChIVUM0IDAzMDksIDEwMDQsIDE4MDQpLg0KKiBOb3QgYmUgYW4gZXhhY3QgZHVwbGljYXRlIG9mIGFub3RoZXIgTkhEIGxha2UgcG9seWdvbi4NCiogSWYgYSBkdXBsaWNhdGUgb2YgYW5vdGhlciBsYWtlIGV4Y2VwdCBmb3IgRkRhdGUgYW5kIFNoYXBlLCB0aGVuIHRoZSBsYWtlIHJldGFpbmVkIG11c3QgaGF2ZSB0aGUgbW9zdCByZWNlbnQgRkRhdGUgKGZlYXR1cmUgZWRpdCBkYXRlKS4NCiogSW50ZXJzZWN0IHRoZSBMQUdPUy1VUyBjb250aWd1b3VzIFUuUy4gbGF5ZXIgKDQ4IHN0YXRlcyBwbHVzIEQuQy4sIFRJR0VSL0xpbmUgZGF0YSkuDQoqIEJlIHJlcHJlc2VudGVkIGFzIHNpbXBsZSBmZWF0dXJlcy0td2UgZGVuc2lmaWVkIHNldmVyYWwgZmVhdHVyZXMgd2l0aCBvbmx5IDIgdmVydGljZXMgdXNpbmcgMTAgbSBhcyB0aGUgbWF4aW11bSBkZXZpYXRpb24gZm9yIGVhY2ggdmVydGV4IGluIG9yZGVyIHRvICJyZXBhaXIiIHRoZWlyIHJlcHJlc2VudGF0aW9uIHRvIG1hdGNoIHRoZSBtYWpvcml0eSBhbmQgdGhlIHN0YW5kYXJkLg0KKiBOb3QgYmUgR3JlYXQgTGFrZXMgb3IgdGhlIHBvcnRpb24gb2YgTGFrZSBTdC4gQ2xhaXIgKE1JL09OKSB0aGF0IGlzIGluIENhbmFkYS4NCiogSGF2ZSBhbiBBcmVhU3FLbSA+IDAuMDA5IChBcmVxU3FLbSBmaWVsZCBpbmNsdWRlZCBpbiBvcmlnaW5hbCBOSERXYXRlcmJvZHkpLg0KKiBIYXZlIGEgcG9seWdvbiBhcmVhIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAxIGhlY3RhcmUgKGNhbGN1bGF0ZWQgZHVyaW5nIExBR09TLVVTIHByb2Nlc3NpbmcgYW5kIG1lYXN1cmVkIGluIHRoZSBBbGJlcnMgVVNHUyBDb25pYyBwcm9qZWN0aW9uKS4gVGhlIGNhbGN1bGF0ZWQgYXJlYSBvY2Nhc2lvbmFsbHkgZG9lcyBub3QgbWF0Y2ggdGhlIGFyZWEgaW4gc3F1YXJlIGtpbG9tZXRlcnMgcHJvdmlkZWQgYnkgTkhELg0KKiBCZSBhc3NpZ25lZCBvbmUgb2YgdGhlIGZvbGxvd2luZyBGZWF0dXJlIENvZGVzIHJlcHJlc2VudGluZyBwZXJtYW5lbnQgd2F0ZXIgYm9kaWVzIGFuZCBub24tYXJ0aWZpY2lhbCB3YXRlciBib2RpZXM6DQogICAgKyAzOTAwMCwzOTAwNCwzOTAwOSwzOTAxMCwzOTAxMSwzOTAxMiAobGFrZXMpDQogICAgKyA0MzYwMCw0MzYxMyw0MzYxNSw0MzYxNyw0MzYxOCw0MzYxOSw0MzYyMSAocmVzZXJ2b2lycykNCiogT25lIGxha2UgaW4gTWV4aWNvIHdhcyByZW1vdmVkIChQZXJtYW5lbnRfSWRlbnRpZmllciA9ICdlMDVlNTdiNS1kMjlmLTRlMWUtODM2OS03M2U1NWY4YmU5ZGYnKSBhZnRlciBpbmRlcGVuZGVudCB2ZXJpZmljYXRpb24gb2YgdGhlIGxha2UgcHJvY2Vzc2luZyB3b3JrZmxvdyByZXZlYWxlZCBhIHNpbmdsZSBkaXNjcmVwYW5jeSBkdWUgdG8gc2xpZ2h0IHZhcmlhdGlvbnMgaW4gb3JkZXIgb2Ygd2hlbiBkYXRhIHByb2plY3Rpb24gd2FzIHBlcmZvcm1lZC4gIA0KDQpUaGUgKipudW1iZXIgb2YgTEFHT1MtVVMgbGFrZXMqKiBhZnRlciBmaWx0ZXJpbmcgaXMgKipgciBucm93KGxhZ29zX3NmKWAqKi4NCg0KIyMgQ29udmVydCBhbmQgU2VsZWN0DQpXZSB3aWxsIHNlbGVjdCBzZXZlcmFsIGNvbHVtbnMgYW5kIGNyZWF0ZSB0d28gYWx0ZXJuYXRlIHJlcHJlc2VudGF0aW9ucyBvZiB0aGUgTEFHT1MtVVMgZGF0YXNldDogY2VudHJvaWRzIGFuZCBubyBnZW9tZXRyeS4NCmBgYHtyIGNvbnZlcnQtbGFnb3MsIGVjaG8gPSBUUlVFfQ0KbGFnb3MgPC0gbGFnb3Nfc2YgJT4lDQogIHNlbGVjdChsYWdvc2xha2VpZCwgDQogICAgICAgICBQZXJtYW5lbnRfSWRlbnRpZmllciwgDQogICAgICAgICBHTklTX0lELCANCiAgICAgICAgIEdOSVNfTmFtZSwgDQogICAgICAgICBSZWFjaENvZGUsIA0KICAgICAgICAgU1RBVEUsIA0KICAgICAgICAgQXJlYVNxS20sIA0KICAgICAgICAgRkRhdGUsDQogICAgICAgICBMQUdPU19Db3VudHlOYW1lID0gTkFNRUxTQUQsDQogICAgICAgICBMQUdPU19Db3VudHlGSVBTID0gRklQUykNCg0KbGFnb3NfY2VudHJvaWQgPC0gbGFnb3Nfc2YgJT4lDQogIHN0X2NlbnRyb2lkKCkgJT4lDQogIHN0X3RyYW5zZm9ybShOQUQ4MykgJT4lDQogIG11dGF0ZShMQUdPU19MYXRpdHVkZU5BRDgzID0gc3RfY29vcmRpbmF0ZXMoLilbLCdZJ10sIA0KICAgICAgICAgTEFHT1NfTG9uZ2l0dWRlTkFEODMgPSBzdF9jb29yZGluYXRlcyguKVssJ1gnXSkgJT4lDQogIHNlbGVjdChsYWdvc2xha2VpZCwgTEFHT1NfTGF0aXR1ZGVOQUQ4MywgTEFHT1NfTG9uZ2l0dWRlTkFEODMpDQoNCmxhZ29zX2RmIDwtIGxhZ29zICU+JSBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkNCmBgYA0KDQojIEdOSVMgKEdlb2dyYXBoaWMgTmFtZXMgSW5mb3JtYXRpb24gU3lzdGVtKQ0KVGhlIEdOSVMgZGF0YXNldCBjb250YWlucyBwbGFjZSBuYW1lcyBmb3IgYSB2YXJpZXR5IG9mIGdlb2dyYXBoaWMgZmVhdHVyZXMsIGluY2x1ZGluZyBsYWtlcywgaW4gdGhlIFVuaXRlZCBTdGF0ZXMuIExvY2F0aW9ucyBhcmUgcmVwcmVzZW50ZWQgYXMgbGF0aXR1ZGUvbG9uZ2l0dWRlIHBhaXJzLiBNb3N0IE5IRCBsYWtlcyBhbHJlYWR5IGhhdmUgYSBHTklTIG5hbWUgYXNzaWduZWQsIGJ1dCBpbiBzb21lIGNhc2VzIHdoZXJlIGxha2VzIGhhZCBtdWx0aXBsZSBuYW1lcywgdGhleSB3ZXJlIG5vdCBhc3NpZ25lZCBhIG5hbWUgaW4gdGhlIE5IRC4gVG8gcG9wdWxhdGUgdGhlIGxha2UgbmFtZSBhcyBmdWxseSBhcyBwb3NzaWJsZSwgd2Ugc2VhcmNoZWQgdGhlIEdOSVMgZGF0YXNldCB0byBib3RoIGFkZCBtaXNzaW5nIG5hbWVzIHdoZXJlIGF2YWlsYWJsZSBhbmQgdG8gZG9jdW1lbnQgbGFrZXMgd2l0aCBtdWx0aXBsZSBuYW1lcywgd2hpY2ggd2UgdGhlbiByZXRhaW4gaW4gTEFHT1MtVVMuDQoNCiMjIEltcG9ydA0KYGBge3IgcmVhZC1nbmlzLCBpbmNsdWRlID0gRkFMU0V9DQojIGduaXNfbGluayA8LSAnaHR0cHM6Ly9nZW9uYW1lcy51c2dzLmdvdi9kb2NzL3N0YXRlZ2F6L05hdGlvbmFsRmlsZV8yMDE4MDIwMS56aXAnICMgY2hhbmdlcyB3aXRoIHVwZGF0ZXMNCiMgdGYgPC0gdGVtcGZpbGUoKQ0KIyBkb3dubG9hZC5maWxlKGduaXNfbGluaywgdGYpDQojIGduaXNfb3JpZyA8LSByZWFkX2RlbGltKHVuemlwKHRmKSwgJ3wnLCBxdW90ZSA9ICIiKQ0KIyAjIFJlbW92ZSB0aGUgYnl0ZSBvcmRlciBtYXJrIGZyb20gZmlyc3QgY29sdW1uIG5hbWUNCiMgbmFtZXMoZ25pc19vcmlnKVsxXSA8LSAiRkVBVFVSRV9JRCINCiMgDQojIHNhdmUoZ25pc19vcmlnLCBmaWxlID0gJy4vcmRhdGEvZ25pc19vcmlnLlJEYXRhJykNCmxvYWQoJy4vcmRhdGEvZ25pc19vcmlnLlJEYXRhJykNCmBgYA0KDQpHbGltcHNlIHRoZSBvcmlnaW5hbCBHTklTIHRhYmxlLg0KYGBge3J9DQpnbGltcHNlKGduaXNfb3JpZywgd2lkdGggPSAxMDApDQpgYGANCg0KDQojIyBGaWx0ZXINCkluY2x1ZGVkIEdOSVMgc2l0ZXMgbXVzdDoNCg0KKiBCZSB3aXRoaW4gb25lIG9mIHRoZSA0OCBjb250aWd1b3VzIHN0YXRlcyBvciBELkMgKEZJUFMgY29kZSBtYXRjaCkNCiogQmUgd2l0aGluIHRoZSByb3VnaCBib3VuZGluZyBib3ggb2YgdGhlIFUuUy4gKGVsaW1pbmF0ZXMgYSBmZXcgc3B1cmlvdXMgbG9jYXRpb25zKQ0KKiBCZSBhc3NpZ25lZCB0aGUgTGFrZSBvciBSZXNlcnZvaXIgRmVhdHVyZSBDbGFzcy4gVGhlc2UgZmVhdHVyZSBjbGFzc2VzIGFnZ3JlZ2F0ZSBhIHZhcmlldHkgb2YgZmVhdHVyZSBuYW1lcyBzdWNoIGFzIExha2UsIExha2VzLCBSZXNlcnZvaXIsIFBvbmQsIFRhbmssIFNsb3VnaCwgTWlsbHBvbmQsIGV0Yy4gX0EgcHJpb3IgYW5hbHlzaXMgc2hvd2VkIHRoYXQgbmVhcmx5IGFsbCBHTklTIG5hbWVzIGFscmVhZHkgYXNzaWduZWQgaW4gdGhlIE5IRCBjb3JyZXNwb25kIHRvIG9uZSBvZiB0aGVzZSB0d28gY2xhc3Nlcywgd2l0aCBtaW5vciB1c2Ugb2YgU3dhbXAsIEZsYXQsIGFuZCByYXJlIHVzZSBvZiBhIHNtYXR0ZXJpbmcgb2Ygb3RoZXIgZmVhdHVyZSBjbGFzc2VzLiBXZSBjaG9vc2UgdG8gZm9jdXMgdGhlIGNyb3Nzd2FsayBvbiB0aGUgbW9zdCByZWxldmFudCBsb2NhdGlvbnMgcmF0aGVyIHRoYW4gY29uc2VydmUgYWxsIHBvc3NpYmxlIGxpbmtzLl8NCiogTm90IGJlIGFzc2lnbmVkIGEgImhpc3RvcmljYWwiIHNpdGUgbmFtZS4gU3VjaCBuYW1lcyBhcmUgc3BhdGlhbGx5IGNvaW5jaWRlbnQgd2l0aCB0aGUgY3VycmVudCBuYW1lLg0KDQpgYGB7ciBmaWx0ZXItZ25pc30NCiMgR2V0IGEgbGlzdCBvZiBzdGF0ZSBjb2RlcyBpbiBvcmRlciB0byBmaWx0ZXIgZm9yIG9ubHkgQ09OVVMgKDQ4IHN0YXRlcyBwbHVzIERDKQ0KZmlwc19maWx0ZXIgPC0gcmVhZF9kZWxpbSgnaHR0cHM6Ly93d3cyLmNlbnN1cy5nb3YvZ2VvL2RvY3MvcmVmZXJlbmNlL3N0YXRlLnR4dCcsICd8JykgJT4lDQogIGZpbHRlcighKFNUQVRFICVpbiUgYygnMDInLCAnMTUnKSB8IFNUQVRFID4gJzU2JykpICU+JSANCiAgc2VsZWN0KFNUVVNBQikNCg0KZ25pc19maWx0ZXJlZCA8LSBnbmlzX29yaWcgJT4lIA0KICBpbm5lcl9qb2luKGZpcHNfZmlsdGVyLCBieSA9IGMoIlNUQVRFX0FMUEhBIiA9ICJTVFVTQUIiKSkgJT4lDQogIGZpbHRlcihQUklNX0xPTkdfREVDIDwgLTY3ICYgUFJJTV9MT05HX0RFQyA+IC0xMjUgJiBQUklNX0xBVF9ERUMgPCA1MCAmIFBSSU1fTEFUX0RFQyA+IDI0KSAlPiUNCiAgZmlsdGVyKEZFQVRVUkVfQ0xBU1MgJWluJSBjKCdMYWtlJywgJ1Jlc2Vydm9pcicpKSAlPiUNCiAgZmlsdGVyKCFncmVwbCgoImhpc3RvcmljYWwiKSwgRkVBVFVSRV9OQU1FKSkNCmBgYA0KVGhlICoqbnVtYmVyIG9mIEdOSVMgc2l0ZXMqKiBmb3IgVS5TLiBsYWtlcyBpcyAqKmByIG5yb3coZ25pc19maWx0ZXJlZClgKiouDQoNCiMjIENvbnZlcnQNCkFjY29yZGluZyB0byB0aGUgW21ldGFkYXRhXShodHRwczovL2dlb25hbWVzLnVzZ3MuZ292L2RvbWVzdGljL2ZhcXMuaHRtKSwgdGhlIGNvb3JkaW5hdGVzIHVzZSB0aGUgTkFEODMgZGF0dW0uIENvbnZlcnQgdGhlIFhZIGRhdGEgdG8gcG9pbnRzLg0KYGBge3IgY29udmVydC1nbmlzfQ0KZ25pc19zZiA8LSBnbmlzX2ZpbHRlcmVkICU+JSANCiAgc3RfYXNfc2YoY29vcmRzID0gYygiUFJJTV9MT05HX0RFQyIsICJQUklNX0xBVF9ERUMiKSkgJT4lIA0KICBzdF9zZXRfY3JzKE5BRDgzKSAlPiUNCiAgc3RfdHJhbnNmb3JtKEFMQkVSU19VU0dTKQ0KYGBgDQoNCiMjIFNlbGVjdA0KU2VsZWN0IHRoZSBGRUFUVVJFX0lELCBGRUFUVVJFX05BTUUsIGFuZCBGRUFUVVJFX0NMQVNTLg0KYGBge3Igc2VsZWN0LWduaXMsIGVjaG8gPSBUUlVFfQ0KZ25pcyA8LSBnbmlzX3NmICU+JQ0KICBzZWxlY3QoRkVBVFVSRV9JRCwgRkVBVFVSRV9OQU1FLCBGRUFUVVJFX0NMQVNTKQ0KYGBgDQoNCiMjIEpvaW4gTEFHT1MtVVMNCkZpcnN0LCBqb2luIExBR09TLVVTIHRvIEdOSVMgYmFzZWQgb24gdGhlIHNoYXJlZCBHTklTX0lELg0KYGBge3Igam9pbi1nbmlzMX0NCmxhZ29zX2duaXNfMSA8LSBnbmlzICU+JQ0KICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkgJT4lDQogIHJpZ2h0X2pvaW4obGFnb3MsIGJ5ID0gYygiRkVBVFVSRV9JRCIgPSAiR05JU19JRCIpKSAlPiUNCiAgcmVuYW1lKA0KICAgIEdOSVNfRmVhdHVyZUNsYXNzID0gRkVBVFVSRV9DTEFTUw0KICAgICkNCmBgYA0KDQpHTklTIE5hbWVzIGNvbnRhaW5lZCBieSB0aGUgcG9seWdvbiBhcmUgYXNzaWduZWQgdG8gdGhlIGxha2UuIEEgbmV3IGNvbHVtbiwgIkxBR09TIExha2UgTmFtZSIgaXMgY3JlYXRlZCBhbmQgbXVsdGlwbGUgbmFtZXMgZm9yIGEgbGFrZSBhcmUgc2VwYXJhdGVkIGJ5IHNlbWktY29sb25zLiBUaGlzIHdpbGwgZWxpbWluYXRlIHRoZSAxOm1hbnkgcmVsYXRpb25zaGlwIGNyZWF0ZWQgaW4gdGhlIGpvaW4uDQoNCmBgYHtyIGpvaW4tZ25pczJ9DQpsYWdvc19nbmlzXzIgPC0gbGFnb3MgJT4lDQogIHN0X2pvaW4oZ25pcykNCg0KbmV3X25hbWVzIDwtIGxhZ29zX2duaXNfMiAlPiUNCiAgc3Rfc2V0X2dlb21ldHJ5KE5VTEwpICU+JQ0KICAjIHRoZSBmb2xsb3dpbmcgaXMgbG9uZy13aW5kZWQgd2F5IHRvIHNheSBwdXQgbmFtZXMgdG9nZXRoZXIgd2l0aCBzZW1pLWNvbG9uDQogICMgZmVlbHMgbGlrZSB0aGlzIHNob3VsZCBiZSBlYXNpZXIgY29kZS4uLg0KICBkaXN0aW5jdChsYWdvc2xha2VpZCwgR05JU19OYW1lLCBGRUFUVVJFX05BTUUpICU+JQ0KICBmaWx0ZXIoKCFpcy5uYShGRUFUVVJFX05BTUUpICYgIGlzLm5hKEdOSVNfTmFtZSkpIHwgR05JU19OYW1lICE9IEZFQVRVUkVfTkFNRSkgJT4lDQogIGdyb3VwX2J5KGxhZ29zbGFrZWlkLCBHTklTX05hbWUpICU+JQ0KICBzdW1tYXJpc2UocGFydGlhbF9uZXdfbmFtZSA9IHBhc3RlKEZFQVRVUkVfTkFNRSwgY29sbGFwc2UgPSAiOyAiKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgdW5pdGUoTEFHT1NfTGFrZU5hbWUsIEdOSVNfTmFtZSwgcGFydGlhbF9uZXdfbmFtZSwgc2VwID0gIjsgIikgJT4lDQogIG11dGF0ZShMQUdPU19MYWtlTmFtZSA9IGdzdWIoJ05BOycsICcnLCBMQUdPU19MYWtlTmFtZSkpDQoNCmxhZ29zX2duaXNfMyA8LSBsYWdvcyAlPiUNCiAgbGVmdF9qb2luKG5ld19uYW1lcywgYnkgPSAibGFnb3NsYWtlaWQiKSAlPiUNCiAgbXV0YXRlKExBR09TX0xha2VOYW1lID0gaWZfZWxzZShpcy5uYShMQUdPU19MYWtlTmFtZSksIEdOSVNfTmFtZSwgTEFHT1NfTGFrZU5hbWUpKQ0KYGBgDQoNCiMjIFNlbGVjdCBhZ2Fpbg0KU2VsZWN0IG9ubHkgdGhlIGRlc2lyZWQgbmFtZXMgYW5kIGlkZW50aWZpZXJzLg0KYGBge3Igc2VsZWN0Mi1nbmlzLCBlY2hvID0gVFJVRX0NCmxhZ29zX2duaXMgPC0gbGFnb3NfZ25pc18zICU+JQ0KICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkgJT4lDQogIHNlbGVjdChsYWdvc2xha2VpZCwgUGVybWFuZW50X0lkZW50aWZpZXIsIEdOSVNfSUQsIEdOSVNfTmFtZSwgUmVhY2hDb2RlLCBTVEFURSwgTEFHT1NfTGFrZU5hbWUsIEFyZWFTcUttKQ0KYGBgDQoNCiMgV1FQIChXYXRlciBRdWFsaXR5IFBvcnRhbC0tU1RPUkVULCBOV0lTLCBhbmQgbW9yZSkNClRoZSBXUVAgQVBJIGFsbG93cyBxdWVyaWVzIG9mIGFsbCB3YXRlciBxdWFsaXR5IG1vbml0b3Jpbmcgc2l0ZXMgdGhhdCBhcmUgc3VibWl0dGVkIHRvIG1ham9yIG5hdGlvbmFsIGRhdGFiYXNlcy4gU2l0ZXMgYXJlIGRlc2NyaWJlZCB3aXRoIGlkZW50aWZpZXJzLCBjb29yZGluYXRlcywgYW5kIG5hbWVzLCBidXQgYXJlIG5vdCBkZWZpbml0aXZlbHkgbGlua2VkIHRvIGFueSBwb2x5Z29uIHJlcHJlc2VudGF0aW9uIG9mIGxha2VzIHRvIG91ciBrbm93bGVkZ2UuIFRoZSBnb2FsIGhlcmUgaXMgdG8gbWF0Y2ggdGhlIFdRUCBpZGVudGlmaWVycyB3aXRoIGxha2VzIGluIExBR09TLVVTLg0KDQojIyBJbXBvcnQNCkdsaW1wc2UgdGhlIG9yaWdpbmFsIFdRUCB0YWJsZS4NCmBgYHtyIHJlYWQtd3FwLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCiMjIFRoaXMgcXVlcnkgY2FuIHJ1biBsb25nDQojIHdxcF9vcmlnIDwtIHdoYXRXUVBzaXRlcyhiQm94ID0gIi0xMjcsMjQsLTY3LDUwIiwgY291bnRyeWNvZGUgPSAiVVMiKQ0KIyBzYXZlKHdxcF9vcmlnLCBmaWxlID0gJy4vcmRhdGEvd3FwX29yaWcuUkRhdGEnKQ0KbG9hZCgnLi9yZGF0YS93cXBfb3JpZy5SRGF0YScpDQpnbGltcHNlKHdxcF9vcmlnLCB3aWR0aCA9IDEwMCkNCmBgYA0KDQojIyBGaWx0ZXINCkluY2x1ZGVkIFdRUCBzaXRlcyBtdXN0Og0KDQoqIEJlIHdpdGhpbiB0aGUgY29udGluZW50YWwgVW5pdGVkIFN0YXRlcyAocm91Z2ggY3V0IHRvIGVsaW1pbmF0ZSBkaXN0YW50IHRlcnJpdG9yaWVzKQ0KKiBCZSBhc3NpZ25lZCBvbmUgb2YgdGhlIGZvbGxvd2luZyBNb25pdG9yaW5nIExvY2F0aW9uIFR5cGVzOiAiTGFrZSIsICJSZXNlcnZvaXIiLCAiUml2ZXJpbmUgSW1wb3VuZG1lbnQiLCAiTGFrZSwgUmVzZXJ2b2lyLCBJbXBvdW5kbWVudCIuIF9UaGVzZSBjYXRlZ29yaWVzIHdlcmUgc2VsZWN0ZWQgaW4gYW4gYW5hbHlzaXMgdGhhdCBhc3Nlc3NlZCBob3cgb2Z0ZW4gdGhlIHNpdGVzIG9mIGVhY2ggdHlwZSB3ZXJlIGxvY2F0ZWQgd2l0aGluIGFuIE5IRCBwb2x5Z29uIGFuZCB3aGV0aGVyIHRoZXkgb2Z0ZW4gaGFkIFNlY2NoaSBkZXB0aCBtZWFzdXJlbWVudHMsIGEgY2hhcmFjdGVyaXN0aWNhbGx5IGxpbW5vbG9naWNhbCBzYW1wbGluZyBwYXJhbWV0ZXIuIE90aGVyIGxvY2F0aW9uIHR5cGVzIGRpZCBzb21ldGltZXMgcmVwcmVzZW50IGRlc2lyYWJsZSBzYW1wbGVzLCBidXQgd2UgY2hvb3NlIHRvIGZvY3VzIHRoZSBjcm9zc3dhbGsgb24gdGhlIG1vc3QgcmVsZXZhbnQgbG9jYXRpb25zIHJhdGhlciB0aGFuIGNvbnNlcnZlIGFsbCBwb3NzaWJsZSBsaW5rcy4gU3RyZWFtLCB3ZXRsYW5kcywgZXN0dWFyaWVzIGFuZCBHcmVhdCBMYWtlcyB3ZXJlIGNhdGVnb3JpY2FsbHkgZXhjbHVkZWQgZGVzcGl0ZSBtZWV0aW5nIHRoZSBhYm92ZSBjcml0ZXJpYSBpbiBzb21lIHBhcnQuXw0KDQpgYGB7ciBmaWx0ZXItd3FwfQ0Kc2VsZWN0ZWRfd3FwX3R5cGVzIDwtIGMoJ0xha2UnLCAnUmVzZXJ2b2lyJywgJ0xha2UsIFJlc2Vydm9pciwgSW1wb3VuZG1lbnQnLCAnUml2ZXJpbmUgSW1wb3VuZG1lbnQnKQ0Kd3FwX2ZpbHRlcmVkIDwtICB3cXBfb3JpZyAlPiUgDQogICAgICAgIGZpbHRlcihMb25naXR1ZGVNZWFzdXJlIDwgLTY3ICYgTG9uZ2l0dWRlTWVhc3VyZSA+IC0xMjUgJiBMYXRpdHVkZU1lYXN1cmUgPCA1MCAmIExhdGl0dWRlTWVhc3VyZSA+IDI0KSAlPiUNCiAgICAgICAgZmlsdGVyKE1vbml0b3JpbmdMb2NhdGlvblR5cGVOYW1lICVpbiUgc2VsZWN0ZWRfd3FwX3R5cGVzKQ0KYGBgDQpUaGUgKipudW1iZXIgb2YgV1FQIHNpdGVzKiogbWVldGluZyB0aGVzZSBjcml0ZXJpYSBpcyAqKmByIG5yb3cod3FwX2ZpbHRlcmVkKWAqKi4NCg0KIyMgQ29udmVydA0KVGhlcmUgaXMgYSBjb2x1bW4gaW4gV1FQIGRhdGEgdG8gaW5kaWNhdGUgdGhlIGNvb3JkaW5hdGUgcmVmZXJlbmNlIHN5c3RlbSAoQ1JTKS4gSG93ZXZlciwgbm90IGFsbCBzaXRlcyBoYWQgYSB2YWx1ZSBpbiB0aGlzIGNvbHVtbi4gUHJpb3IgYW5hbHlzaXMgc2hvd2VkIHRoYXQgdGhlIG1vc3QgY29tbW9ubHkgaW5kaWNhdGVkIGNvbHVtbiB3YXMgTkFEODMsIGFuZCBzbyBmb3IgYWxsIHNpdGVzIHdpdGggYW4gdW5rbm93biBvciByYXJlIENSUyAoZGlzdGFudCBVLlMuIHRlcnJpdG9yaWVzKSwgdGhlIE5BRDgzIGRhdHVtIHdhcyBpbXB1dGVkIGluc3RlYWQuIA0KDQpGb3Igc2l0ZXMgd2l0aCBvbmUgb2YgdGhlIGZvbGxvd2luZyBvdGhlciBkYXR1bXMsIHRoZSBhY3R1YWwgZGF0dW0gc3BlY2lmaWNhdGlvbiBpcyBwcmVzZXJ2ZWQ6IE5BRDI3LCBXR1M4NC4gSW4gb3JkZXIgdG8gbWFuYWdlIHRoZSBwcm9qZWN0aW9ucyBiZWZvcmUgdHJhbnNmb3JtaW5nIGFsbCB0aGUgZGF0YSB0byBhIGNvbW1vbiBwcm9qZWN0aW9uLCBBbGJlcnMgRXF1YWwgQXJlYSBDb25pYyAoVVNHUyksIHdlIHNwbGl0IHVwIHRoZSBkYXRhc2V0LCBwcm9qZWN0ZWQgdGhlIHNpdGVzIGluIGVhY2ggZGF0dW0sIGNvbnZlcnRlZCBhbGwgcm93cyB0byBBbGJlcnMgVVNHUywgYW5kIHRoZW4gcmV1bml0ZWQgYWxsIHJvd3MgYXQgdGhlIGVuZC4NCmBgYHtyIGNvbnZlcnQtd3FwfQ0Kd3FwX2RhdHVtcyA8LSB3cXBfZmlsdGVyZWQgJT4lIG11dGF0ZShBc3NpZ25lZENSUyA9IGNhc2Vfd2hlbigNCiAgICAgICAgSG9yaXpvbnRhbENvb3JkaW5hdGVSZWZlcmVuY2VTeXN0ZW1EYXR1bU5hbWUgPT0gJ05BRDgzJyB+ICdOQUQ4MycsDQogICAgICAgIEhvcml6b250YWxDb29yZGluYXRlUmVmZXJlbmNlU3lzdGVtRGF0dW1OYW1lID09ICdOQUQyNycgfiAnTkFEMjcnLA0KICAgICAgICBIb3Jpem9udGFsQ29vcmRpbmF0ZVJlZmVyZW5jZVN5c3RlbURhdHVtTmFtZSA9PSAnV0dTODQnIH4gJ1dHUzg0JywNCiAgICAgICAgSG9yaXpvbnRhbENvb3JkaW5hdGVSZWZlcmVuY2VTeXN0ZW1EYXR1bU5hbWUgPT0gJ1dHUzcyJyB+ICdXR1M3MicsDQogICAgICAgIFRSVUUgfiAnTkFEODMnDQopKQ0KDQp3cXBfbmFkODMgPC0gIGZpbHRlcih3cXBfZGF0dW1zICwgQXNzaWduZWRDUlMgPT0gJ05BRDgzJykgJT4lDQogICAgICAgICAgICAgIHN0X2FzX3NmKGNvb3JkcyA9IGMoIkxvbmdpdHVkZU1lYXN1cmUiLCAiTGF0aXR1ZGVNZWFzdXJlIikpICU+JSANCiAgICAgICAgICAgICAgc3Rfc2V0X2NycyhOQUQ4MykgJT4lDQogICAgICAgICAgICAgIHN0X3RyYW5zZm9ybShBTEJFUlNfVVNHUykNCg0Kd3FwX25hZDI3IDwtICBmaWx0ZXIod3FwX2RhdHVtcyAsIEFzc2lnbmVkQ1JTID09ICdOQUQyNycpICU+JQ0KICAgICAgICAgICAgICBzdF9hc19zZihjb29yZHMgPSBjKCJMb25naXR1ZGVNZWFzdXJlIiwgIkxhdGl0dWRlTWVhc3VyZSIpKSAlPiUgDQogICAgICAgICAgICAgIHN0X3NldF9jcnMoTkFEMjcpICU+JQ0KICAgICAgICAgICAgICBzdF90cmFuc2Zvcm0oQUxCRVJTX1VTR1MpDQoNCndxcF93Z3M4NCA8LSAgZmlsdGVyKHdxcF9kYXR1bXMgLCBBc3NpZ25lZENSUyA9PSAnV0dTODQnKSAlPiUNCiAgICAgICAgICAgICAgc3RfYXNfc2YoY29vcmRzID0gYygiTG9uZ2l0dWRlTWVhc3VyZSIsICJMYXRpdHVkZU1lYXN1cmUiKSkgJT4lIA0KICAgICAgICAgICAgICBzdF9zZXRfY3JzKFdHUzg0KSAlPiUNCiAgICAgICAgICAgICAgc3RfdHJhbnNmb3JtKEFMQkVSU19VU0dTKQ0KDQojIHdxcF93Z3M3MiA8LSAgZmlsdGVyKHdxcF9kYXR1bXMgLCBBc3NpZ25lZENSUyA9PSAnV0dTNzInKSAlPiUNCiMgICAgICAgICAgICAgICBzdF9hc19zZihjb29yZHMgPSBjKCJMb25naXR1ZGVNZWFzdXJlIiwgIkxhdGl0dWRlTWVhc3VyZSIpKSAlPiUgDQojICAgICAgICAgICAgICAgc3Rfc2V0X2NycyhXR1M3MikgJT4lDQojICAgICAgICAgICAgICAgc3RfdHJhbnNmb3JtKEFMQkVSU19VU0dTKQ0KDQp3cXBfc2YgPC0gcmJpbmQod3FwX25hZDgzLCB3cXBfbmFkMjcsIHdxcF93Z3M4NCkNCg0KIyBDbGVhbnVwDQpybSh3cXBfbmFkODMsIHdxcF9uYWQyNywgd3FwX3dnczg0KQ0KI3NhdmUod3FwX3NmLCBmaWxlID0gIi4vcmRhdGEvd3FwX3NmLlJEYXRhIikNCmBgYA0KDQojIyBTZWxlY3QNCmBgYHtyIHNlbGVjdC13cXAsIGVjaG8gPSBUUlVFfQ0Kd3FwIDwtIHdxcF9zZiAlPiUNCiAgc2VsZWN0KE9yZ2FuaXphdGlvbklkZW50aWZpZXIsIE1vbml0b3JpbmdMb2NhdGlvbklkZW50aWZpZXIsIE1vbml0b3JpbmdMb2NhdGlvbk5hbWUsIFByb3ZpZGVyTmFtZSwgTW9uaXRvcmluZ0xvY2F0aW9uVHlwZU5hbWUpDQpgYGANCg0KIyMgSm9pbiBMQUdPUy1VUw0KMSkgV1FQIHNpdGVzIHdpdGhpbiBhIGxha2UgcG9seWdvbiBhcmUgbGlua2VkIHRvIHRoYXQgcG9seWdvbi4NCmBgYHtyIGpvaW4td3FwMX0NCmxhZ29zX3dxcF8wbSA8LSB3cXAgJT4lDQogIHN0X2pvaW4obGFnb3MpICU+JQ0KICByZW5hbWUobGFnb3NsYWtlaWRfMG0gPSBsYWdvc2xha2VpZCkgJT4lDQogIG11dGF0ZShzaGFyZWRfd29yZHNfMG0gID0gbGlzdF9zaGFyZWRfd29yZHMoR05JU19OYW1lLCBNb25pdG9yaW5nTG9jYXRpb25OYW1lKSkNCmBgYA0KDQpFeGFtaW5hdGlvbiBvZiBzaGFyZWQgd29yZHMgaW4gdGhlIG5hbWVzOiBBbGwgbGFrZXMgd2hlcmUgdHdvIG5hbWVzIGFyZSBhdmFpbGFibGUgYnV0IGRvbid0IHNoYXJlIHdvcmRzLiBTb21lIG9mIHRoZXNlIGxha2VzIGhhdmUgbmFtZXMgZm9sbG93aW5nIHNvbWUga2luZCBvZiB0ZWNobmljYWwgZm9ybSwgYnV0IG90aGVycyBzZWVtcyB0byBzdWdnZXN0IG1pcy1yZWZlcmVuY2VkIGxha2VzIGV2ZW4gdGhvdWdoIHRoZSBwb2ludCBmb3IgdGhlIHNpdGUgZmFsbHMgaW5zaWRlIHRoZSBsYWtlLiBTb21lIGV4YW1wbGVzICh6b29tIGluIHRvIHNlZSBOSEQgZGV0YWlsIGFwcGVhcik6DQpgYGB7ciBqb2luLXdxcDJ9DQp3ZWlyZF9tYXRjaGVzIDwtIGxhZ29zX3dxcF8wbSAlPiUNCiAgZmlsdGVyKCFpcy5uYShHTklTX05hbWUpICYgIWlzLm5hKE1vbml0b3JpbmdMb2NhdGlvbk5hbWUpICYgaXMubmEoc2hhcmVkX3dvcmRzXzBtKSkNCg0Kd2VpcmRfbWF0Y2hlcyAlPiUNCiAgc2FtcGxlX24oMjUpICU+JQ0KICBzdF90cmFuc2Zvcm0oV0dTODQpICU+JQ0KICBsZWFmbGV0KCkgJT4lDQogIGFkZFNjYWxlQmFyKCkgJT4lDQogIGFkZENpcmNsZU1hcmtlcnMocmFkaXVzID0gMiwgbGFiZWwgPSB+TW9uaXRvcmluZ0xvY2F0aW9uTmFtZSkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQ0KICBhZGRXTVNUaWxlcyhOSERfVVJMLCBhdHRyaWJ1dGlvbiA9IFVTR1NfQVRUUiwgb3B0aW9ucyA9IFdNU1RpbGVPcHRpb25zKGZvcm1hdCA9ICJpbWFnZS9wbmciLCB0cmFuc3BhcmVudCA9IFRSVUUpLCBsYXllcnMgPSAiMCwxIikNCmBgYA0KDQoyKSBXUVAgc2l0ZXMgY2FuIGJlIGpvaW5lZCB0byBhIGxha2UgcG9seWdvbiBpZiB0aGV5IGFyZSB3aXRoaW4gMTAgbWV0ZXJzIG9mIGl0Lg0KYGBge3Igam9pbi13cXAzfQ0Kd3FwX3NpdGVzX3dpdGhfMG1fbWF0Y2ggPC0gbGFnb3Nfd3FwXzBtICU+JQ0KICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkgJT4lDQogIGZpbHRlcighaXMubmEobGFnb3NsYWtlaWRfMG0pKSAlPiUNCiAgZGlzdGluY3QoTW9uaXRvcmluZ0xvY2F0aW9uSWRlbnRpZmllcikNCg0KIyMgTXVjaCBzbG93ZXIgdG8gdGhlIHBvaW50IG9mIG5vdCB3b3JraW5nIG91dCBmb3IgbWUNCiMgbGFnb3Nfd3FwXzEwbSA8LSB3cXAgJT4lDQojICAgYW50aV9qb2luKHdxcF9zaXRlc193aXRoXzBtX21hdGNoLCBieSA9ICJNb25pdG9yaW5nTG9jYXRpb25JZGVudGlmaWVyIikgJT4lDQojICAgc3Rfam9pbihsYWdvcywgc3RfaXNfd2l0aGluX2Rpc3RhbmNlLCBkaXN0PTEwKQ0KDQojIFN0aWxsIDYuNSBtaW51dGVzIG9uIG15IG1hY2hpbmUgd2hlbiBJIHRpbWVkIGl0LCBhbmQgbW9yZSBpbiBsYXRlciBydW5zLg0KIyBsYWdvc18xMCA8LSBzdF9idWZmZXIobGFnb3MsIDEwKQ0KIyBzYXZlKGxhZ29zXzEwLCBmaWxlID0gIi4vcmRhdGEvbGFnb3NfMTAuUkRhdGEiKQ0KbG9hZCgnLi9yZGF0YS9sYWdvc18xMC5SRGF0YScpDQoNCmxhZ29zX3dxcF8xMG0gPC0gd3FwICU+JQ0KICBhbnRpX2pvaW4od3FwX3NpdGVzX3dpdGhfMG1fbWF0Y2gsIGJ5ID0gIk1vbml0b3JpbmdMb2NhdGlvbklkZW50aWZpZXIiKSAlPiUNCiAgc3Rfam9pbihsYWdvc18xMCkgJT4lDQogIHJlbmFtZShsYWdvc2xha2VpZF8xMG0gPSBsYWdvc2xha2VpZCkgJT4lDQogIG11dGF0ZShzaGFyZWRfd29yZHNfMTBtICA9IGxpc3Rfc2hhcmVkX3dvcmRzKEdOSVNfTmFtZSwgTW9uaXRvcmluZ0xvY2F0aW9uTmFtZSkpICU+JQ0KICBzZWxlY3QoTW9uaXRvcmluZ0xvY2F0aW9uSWRlbnRpZmllciwgbGFnb3NsYWtlaWRfMTBtLCBzaGFyZWRfd29yZHNfMTBtKQ0Kcm0obGFnb3NfMTApDQpgYGANCg0KMykgT3RoZXIgc2l0ZXMgY2FuIGJlIGpvaW5lZCBpZiB0aGV5IGFyZSB3aXRoaW4gMTAwIG0gb2YgYSBsYWtlIHBvbHlnb24sIG5vdCB3aXRoaW4gYW4gTkhEQXJlYSBTdHJlYW1SaXZlciBmZWF0dXJlLCBhbmQgc2hhcmUgbmFtZSB3b3JkcyBvdGhlciB0aGFuICJsYWtlIiwgInJlc2Vydm9pciIsIGV0Yy4NCmBgYHtyIGpvaW4td3FwNH0NCndxcF9zaXRlc193aXRoXzEwbV9tYXRjaCA8LSBsYWdvc193cXBfMTBtICU+JQ0KICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkgJT4lDQogIGZpbHRlcighaXMubmEobGFnb3NsYWtlaWRfMTBtKSkgJT4lDQogIGRpc3RpbmN0KE1vbml0b3JpbmdMb2NhdGlvbklkZW50aWZpZXIpICU+JQ0KICB1bmlvbih3cXBfc2l0ZXNfd2l0aF8wbV9tYXRjaCkNCg0KIyAjIDE5IG1pbnV0ZXMgb24gbXkgbWFjaGluZS4gTG9hZCBpbWFnZSBpbnN0ZWFkLg0KIyBsYWdvc18xMDAgPC0gc3RfYnVmZmVyKGxhZ29zLCAxMDApDQojIHNhdmUobGFnb3NfMTAwLCBmaWxlID0gIi4vcmRhdGEvbGFnb3NfMTAuUkRhdGEiKQ0KbG9hZCgnLi9yZGF0YS9sYWdvc18xMDAuUkRhdGEnKQ0KDQpsYWdvc193cXBfMTAwbSA8LSB3cXAgJT4lDQogIGFudGlfam9pbih3cXBfc2l0ZXNfd2l0aF8xMG1fbWF0Y2gsIGJ5ID0gIk1vbml0b3JpbmdMb2NhdGlvbklkZW50aWZpZXIiKSAlPiUNCiAgc3Rfam9pbihsYWdvc18xMDApICU+JQ0KICByZW5hbWUobGFnb3NsYWtlaWRfMTAwbSA9IGxhZ29zbGFrZWlkKSAlPiUNCiAgbXV0YXRlKHNoYXJlZF93b3Jkc18xMDBtICA9IGxpc3Rfc2hhcmVkX3dvcmRzKEdOSVNfTmFtZSwgTW9uaXRvcmluZ0xvY2F0aW9uTmFtZSkpICU+JQ0KICBzZWxlY3QoTW9uaXRvcmluZ0xvY2F0aW9uSWRlbnRpZmllciwgbGFnb3NsYWtlaWRfMTAwbSwgc2hhcmVkX3dvcmRzXzEwMG0pDQpybShsYWdvc18xMDApDQpgYGANCg0KSm9pbiB0aGVtIGFsbCB1cCBpbnRvIG9uZSBhbmQgZW5mb3JjZSB0aGUgcnVsZXMuDQpgYGB7ciBqb2luLXdxcDV9DQpsYWdvc193cXBfYWxsIDwtIGxhZ29zX3dxcF8wbSAlPiUNCiAgbGVmdF9qb2luKHN0X3NldF9nZW9tZXRyeShsYWdvc193cXBfMTBtLCBOVUxMKSwgYnkgPSAiTW9uaXRvcmluZ0xvY2F0aW9uSWRlbnRpZmllciIpICU+JQ0KICBsZWZ0X2pvaW4oc3Rfc2V0X2dlb21ldHJ5KGxhZ29zX3dxcF8xMDBtLCBOVUxMKSwgYnkgPSAiTW9uaXRvcmluZ0xvY2F0aW9uSWRlbnRpZmllciIpICU+JQ0KICBtdXRhdGUoTGlua2VkX2xhZ29zbGFrZWlkID0gY29hbGVzY2UobGFnb3NsYWtlaWRfMG0sIGxhZ29zbGFrZWlkXzEwbSksDQogICAgICAgICAgU2hhcmVkX1dvcmRzID0gY29hbGVzY2Uoc2hhcmVkX3dvcmRzXzBtLCBzaGFyZWRfd29yZHNfMTBtKSkgJT4lDQogIG11dGF0ZShMaW5rZWRfbGFnb3NsYWtlaWQgPSBpZl9lbHNlKCFpcy5uYShzaGFyZWRfd29yZHNfMTAwbSksIGxhZ29zbGFrZWlkXzEwMG0sIExpbmtlZF9sYWdvc2xha2VpZCksDQogICAgICAgICBTaGFyZWRfV29yZHMgPSBjb2FsZXNjZShzaGFyZWRfd29yZHNfMTAwbSwgU2hhcmVkX1dvcmRzKSkNCmBgYA0KDQpIb3cgbWFueSBqb2lucyB3ZXJlIG1hZGUgZm9yIGVhY2ggbWV0aG9kPw0KYGBge3Igam9pbi13cXA2fQ0Kbl8wIDwtIGxhZ29zX3dxcF9hbGwgJT4lIGZpbHRlcighaXMubmEobGFnb3NsYWtlaWRfMG0pKSAlPiUgbnJvdygpDQpuXzEwIDwtIGxhZ29zX3dxcF9hbGwgJT4lIGZpbHRlcighaXMubmEobGFnb3NsYWtlaWRfMTBtKSkgJT4lIG5yb3coKQ0Kbl8xMDAgPC0gbGFnb3Nfd3FwX2FsbCAlPiUgZmlsdGVyKCFpcy5uYShMaW5rZWRfbGFnb3NsYWtlaWQpICYgTGlua2VkX2xhZ29zbGFrZWlkID09IGxhZ29zbGFrZWlkXzEwMG0pICU+JSBucm93KCkNCmBgYA0KDQorICoqTm8gc2VhcmNoIGRpc3RhbmNlOioqIGByIG5fMGANCisgKioxMCBtIHNlYXJjaCBkaXN0YW5jZToqKiBgciBuXzEwYA0KKyAqKjEwMCBtIHNlYXJjaCBkaXN0YW5jZSAod2l0aCBuYW1lIGNvbmRpdGlvbik6KiogYHIgbl8xMDBgDQoNClNvbWUgbGFrZXMgaGF2ZSBhIHZlcnkgaGlnaCBudW1iZXIgb2Ygc2FtcGxpbmcgc2l0ZXMuIFRoaXMgbWFwIHNob3dzIHNvbWUgZXhhbXBsZXMgb2YgbGFrZXMgd2l0aCBvdmVyIDUwIHNhbXBsaW5nIHNpdGVzIHN0b3JlZC4NCmBgYHtyIGpvaW4td3FwN30NCm51bV9wdHMgPC0gbGFnb3Nfd3FwXzBtICU+JQ0KICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkgJT4lDQogIGZpbHRlcighaXMubmEoTW9uaXRvcmluZ0xvY2F0aW9uSWRlbnRpZmllcikpICU+JQ0KICBncm91cF9ieShsYWdvc2xha2VpZF8wbSwgU1RBVEUsIEdOSVNfTmFtZSkgJT4lDQogIHN1bW1hcml6ZShuID0gbigpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBhcnJhbmdlKC1uKQ0KDQppbnRlbnNlX2xha2VzIDwtIG51bV9wdHMgJT4lDQogIGZpbHRlcihuPjUwKSAlPiUNCiAgc2FtcGxlX24oNSkgJT4lDQogIGlubmVyX2pvaW4oc3Rfc2V0X2dlb21ldHJ5KGxhZ29zX3dxcF8wbSwgTlVMTCksIGJ5ID0gImxhZ29zbGFrZWlkXzBtIikgJT4lDQogIGlubmVyX2pvaW4od3FwX3NmLCBieSA9ICJNb25pdG9yaW5nTG9jYXRpb25JZGVudGlmaWVyIikgJT4lDQogIHN0X2FzX3NmKCkNCg0KbWFwdmlldyhpbnRlbnNlX2xha2VzKQ0KYGBgDQoNCg0KDQojIyBTZWxlY3QgYWdhaW4NClJldGFpbiBvbmx5IGNvbHVtbnMgcmVsZXZhbnQgdG8gY3Jvc3N3YWxrLg0KYGBge3Igc2VsZWN0Mi13cXAsIGVjaG8gPSBUUlVFfQ0KbGFnb3Nfd3FwIDwtIGxhZ29zX3dxcF9hbGwgJT4lDQogIHN0X3NldF9nZW9tZXRyeShOVUxMKSAlPiUNCiAgc2VsZWN0KE9yZ2FuaXphdGlvbklkZW50aWZpZXIsIE1vbml0b3JpbmdMb2NhdGlvbklkZW50aWZpZXIsIE1vbml0b3JpbmdMb2NhdGlvbk5hbWUsIFByb3ZpZGVyTmFtZSwgTGlua2VkX2xhZ29zbGFrZWlkKQ0KYGBgDQoNCiMgTkhEUGx1c1YyICh2YWx1ZS1hZGRlZCBOYXRpb25hbCBIeWRyb2dyYXBoeSBEYXRhc2V0IGFuZCBiYXNpcyBmb3IgTmF0aW9uYWwgTGFrZXMgQXNzZXNzbWVudCwgTGFrZUNhdCkNClRoZSBtZWRpdW0tcmVzb2x1dGlvbiBOSEQgY29udGFpbnMgYSBwb3B1bGFyIG1lZGl1bS1yZXNvbHV0aW9uIHJlcHJlc2VudGF0aW9uIG9mIGxha2VzIGFuZCB0aGVpciBoeWRyb2dyYXBoaWMgY29udGV4dC4gQmVjYXVzZSB0aGUgaGlnaC1yZXNvbHV0aW9uIE5IRCBkYXRhIHdlcmUgdXNlZCB0byBnZW5lcmF0ZSBMQUdPUy1VUywgd2UgbXVzdCBmaW5kIGEgY29ubmVjdGlvbiBiZXR3ZWVuIHRoZSBkYXRhc2V0cy4gVGhpcyBjb25uZWN0aW9uIGlzIHRoZSByZWFjaCBjb2RlLCBhIDE0LWRpZ2l0IGlkZW50aWZpZXIgdXNlZCB0byBpZGVudGlmeSBlYWNoIHJlYWNoIGFzIHBhcnQgb2YgYSBsaW5lYXIgcmVmZXJlbmNpbmcgc3lzdGVtLiBSZWFjaENvZGVzIG11c3Qgc29tZXRpbWVzIGJlIG1vZGlmaWVkIChzcGxpdCwgam9pbmVkLCByZS1hc3NpZ25lZCwgZGVsZXRlZCkuIFRoZSBOSERSZWFjaENyb3NzUmVmZXJlbmNlIHRhYmxlIHRyYWNrcyB0aGVzZSBjaGFuZ2VzIGFuZCBzaG93cyB0aGUgbmV3IGFuZCBvbGQgUmVhY2hDb2RlLiANCg0KIyMgSW1wb3J0DQpUaGUgdmVyc2lvbiBvZiB0aGUgTkhEUmVhY2hDcm9zc1JlZmVyZW5jZSB0YWJsZSB0aGF0IHdlIHVzZSBoYXMgYWxyZWFkeSBiZWVuIGZpbHRlcmVkIHRvIGluY2x1ZGUgb25seSB0aGUgcmVhY2ggY29kZXMgZm9yIGxha2VzIGFuZCByZXNlcnZvaXJzIGluIHRoZSBOSEQgSFIgKGUuZy4gc3RyZWFtcywgd2V0bGFuZHMsIGV0Yy4gd2VyZSByZW1vdmVkKSB0byByZWR1Y2UgdGhlIHRhYmxlIHNpemUuIFlvdSBjb3VsZCB1c2UgdGhlIGZ1bGwgb3JpZ2luYWwgdGFibGUgd2l0aCBubyBjaGFuZ2UgdG8gdGhlIHJlc3VsdHMuDQoNCkdsaW1wc2UgdGhlIE5IRCB0YWJsZS4NCmBgYHtyIHJlYWQtbmhkfQ0KIyBuaGRfcGx1c19vcmlnIDwtIHN0X3JlYWQoJ0Q6L05vdF9Db250TGltbm8vTkhEUGx1cyBWMi9OSERQbHVzTmF0aW9uYWxEYXRhL05IRFBsdXNWMjFfTmF0aW9uYWxfU2VhbWxlc3MuZ2RiJywgJ05IRFdhdGVyYm9keScsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkgJT4lDQojICAgbXV0YXRlKEdOSVNfSUQgPSBhcy5udW1lcmljKEdOSVNfSUQpKSAjIHRvIG1hdGNoIHRoZSBvdGhlcnMNCiMgc2F2ZShuaGRfcGx1c19vcmlnLCBmaWxlID0gJy4vcmRhdGEvbmhkX3BsdXNfb3JpZy5SRGF0YScpDQpsb2FkKCcuL3JkYXRhL25oZF9wbHVzX29yaWcuUkRhdGEnKQ0KZ2xpbXBzZShuaGRfcGx1c19vcmlnLCB3aWR0aCA9IDEwMCkNCmBgYA0KDQpHbGltcHNlIHRoZSBOSERSZWFjaENyb3NzUmVmZXJlbmNlIHRhYmxlLg0KYGBge3J9DQojIyBJbiBvcmRlciB0byByZWFkIHRhYmxlIHdpdGggT3BlbkZpbGVHREIsIG5lZWQgc2YgZnJvbSBHaXRodWIgPiAyMDE4LTAyLTExIHNpbmNlIHRoaXMgY29tbWl0DQojIyBodHRwczovL2dpdGh1Yi5jb20vci1zcGF0aWFsL3NmL2NvbW1pdC83N2EzMWYyOTg5YTFkMjE3NDM4ZmI2MjlhYzM0ZDdlZjMxYmFhOWMyDQojIyBvciBzZiA+IDAuNi0xIG9uIENSQU4gdG8gYmUgcmVsZWFzZWQgTWFyY2ggMjAxOA0KIyBuaGRfeHJlZiA8LSBzdF9yZWFkKCdEOi9Db250aW5lbnRhbF9MaW1ub2xvZ3kvRGF0YV9Xb3JraW5nL0xBR09TX1VTX1ByZWRlY2Vzc29ycy5nZGInLCAnTkhEUmVhY2hDcm9zc1JlZmVyZW5jZV9sYWtlcycpICU+JQ0KIyAgIHNlbGVjdChPbGRSZWFjaENvZGUsIE9sZFJlYWNoRGF0ZSwgTmV3UmVhY2hDb2RlLCBOZXdSZWFjaERhdGUpDQojIHNhdmUobmhkX3hyZWYsIGZpbGUgPSAnLi9yZGF0YS9uaGRfeHJlZi5SRGF0YScpDQpsb2FkKCcuL3JkYXRhL25oZF94cmVmLlJEYXRhJykNCg0KZ2xpbXBzZShuaGRfeHJlZiwgd2lkdGggPSAxMDApDQpgYGANCg0KIyMgRmlsdGVyDQpXZSBjYW4ndCB1c2UgdGhlIGpvaW4gbWV0aG9kIHRvIGNvbm5lY3QgdG8gYW55IE5IRFBsdXNWMiBsYWtlcyB0aGF0IGRvbid0IGhhdmUgUkVBQ0hDT0RFIHBvcHVsYXRlZC4gV2Ugd2lsbCByZXZpc2l0IHRoZXNlIGxha2VzIGFsb25nIHdpdGggb3RoZXJzIHRoYXQgd29uJ3QgY29ubmVjdCBsYXRlci4NCmBgYHtyIGZpbHRlci1uaGR9DQpuaGRfcGx1c19maWx0ZXJlZCA8LSBuaGRfcGx1c19vcmlnICU+JQ0KICBmaWx0ZXIoUkVBQ0hDT0RFICE9ICcgJykNCg0KIyBUaGlzIGJpdCBpcyBvcnBoYW5lZCBmb3Igbm93IHVubGVzcyB3ZSBtYWtlIGEgdGhpcmQgY29ubmVjdGlvbiBhdHRlbXB0DQojIG5oZF9wbHVzX2FsdF9maWx0ZXJlZCA8LSBuaGRfcGx1c19vcmlnDQpgYGANCg0KIyMgQ29udmVydA0KVGhlc2UgZGF0YSBhcmUgYWxyZWFkeSBzcGF0aWFsIHBvbHlnb25zIGFuZCB3ZSB3YW50IGEgZGF0YXNldCB3aXRoIG5vIGdlb21ldHJ5IGluc3RlYWQuDQpgYGB7ciBjb252ZXJ0LW5oZH0NCm5oZF9wbHVzX2RmIDwtIG5oZF9wbHVzX2ZpbHRlcmVkICU+JQ0KICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkNCmBgYA0KDQojIyBTZWxlY3QNCmBgYHtyIHNlbGVjdC1uaGQsIGVjaG8gPSBUUlVFfQ0KbmhkX3BsdXMgPC0gbmhkX3BsdXNfZGYgJT4lDQogIHNlbGVjdChDT01JRCwgRkRBVEUsIEdOSVNfSUQsIEdOSVNfTkFNRSwgUkVBQ0hDT0RFLCBBUkVBU1FLTSkNCmBgYA0KDQojIyBKb2luIExBR09TLVVTDQpUaGlzIGpvaW4gY3JlYXRlcyBtYW55Om1hbnkgcmVsYXRpb25zaGlwcy4gQSBzY2FudCBmZXcgUmVhY2hDb2RlcyBpbiB0aGUgTEFHT1MtVVMgcG9wdWxhdGlvbiBhcmUgYXNzb2NpYXRlZCB3aXRoIHR3byBQZXJtYW5lbnRfSWRlbnRpZmllcnMgYmVmb3JlIHRoZSBqb2luLiBNb3N0IHJlYWNoIGNvZGVzIGRvbid0IGhhdmUgYW4gZW50cnkgaW4gdGhlIGNyb3NzIHJlZmVyZW5jZSB0YWJsZSwgc3VnZ2VzdGluZyB0aGF0IGxha2VzIHN0aWxsIGhvbGRpbmcgdGhlaXIgb3JpZ2luYWwgcmVhY2ggY29kZSBzaG91bGQgaGF2ZSB0aGUgc2FtZSByZWFjaCBjb2RlIGluIGFueSB2ZXJzaW9uIG9mIHRoZSBOSEQuDQoNCmBgYHtyIGpvaW4tbmhkMX0NCiMgSm9pbiB0byBOSERSZWFjaENyb3NzUmVmZXJlbmNlIChuaGRfeHJlZikNCmxhZ29zX25oZHggPC0gbGFnb3NfZGYgJT4lDQogIGZpbHRlcighaXMubmEoUmVhY2hDb2RlKSkgJT4lDQogIGxlZnRfam9pbihuaGRfeHJlZiwgYnkgPSBjKCJSZWFjaENvZGUiID0gIk5ld1JlYWNoQ29kZSIpKQ0KICAjbXV0YXRlKGhhc194cmVmID0gaWZfZWxzZSghaXMubmEoT2xkUmVhY2hDb2RlKSwgJ1knLCAnTicpKQ0KDQpub194cmVmIDwtIGxhZ29zX2RmICU+JQ0KICBmaWx0ZXIoIWlzLm5hKFJlYWNoQ29kZSkpICU+JQ0KICBhbnRpX2pvaW4obmhkX3hyZWYsIGJ5ID0gYygiUmVhY2hDb2RlIiA9ICJOZXdSZWFjaENvZGUiKSkgJT4lDQogIG5yb3coKQ0KDQpuZXdfcmVhY2hfb25seSA8LSBsYWdvc19uaGR4ICU+JQ0KICBmaWx0ZXIoaXMubmEoT2xkUmVhY2hDb2RlKSkgJT4lDQogIG5yb3coKQ0KYGBgDQoqKmByIG5ld19yZWFjaF9vbmx5YCoqIHJlYWNoIGNvZGVzIGhhdmUgb25seSBhIG5ldyByZWFjaCBjb2RlIGluIE5IRFJlYWNoQ3Jvc3NSZWZlcmVuY2UgYW5kIHRoZSBPbGRSZWFjaENvZGUgaXMgbWlzc2luZy4gSW4gb3RoZXIgd29yZHMsIGFib3V0ICoqYHIgcm91bmQoMTAwKm5ld19yZWFjaF9vbmx5L25yb3cobGFnb3NfZGYpLCAyKWAlKiogb2YgTEFHT1MtVVMgbGFrZXMgaGF2ZSBuZXZlciBjaGFuZ2VkIHJlYWNoIGNvZGVzLiBBYm91dCBhIHRlbnRoIG9mIHRoZSBsYWtlcyBoYXZlIG5vIGVudHJ5IGluIE5IRFJlYWNoQ3Jvc3NSZWZlcmVuY2UsIHN1Z2dlc3RpbmcgdGhpcyB0YWJsZSBpcyB1c3VhbGx5IGJ1dCBub3QgYWx3YXlzIHBvcHVsYXRlZCB3aGVuIG5ldyByZWFjaCBjb2RlcyBhcmUgYXNzaWduZWQuDQoNCmBgYHtyIGpvaW4tbmhkMn0NCiMgSm9pbiBvbiBvbGQgcmVhY2ggY29kZXMNCmxhZ29zX25oZF8xIDwtIGxhZ29zX25oZHggJT4lDQogIGZpbHRlcighaXMubmEoT2xkUmVhY2hDb2RlKSkgJT4lDQogIGxlZnRfam9pbihuaGRfcGx1cywgYnkgPSBjKCJPbGRSZWFjaENvZGUiID0gIlJFQUNIQ09ERSIpLCBzdWZmaXggPSBjKCJfSFIiLCAiX01SIikpDQoNCiMgSm9pbiBvbiBuZXcgcmVhY2ggY29kZXMgKGFib3V0IGEgZG96ZW4gbGFrZXMgd2lsbCBsaW5rIGluIGJvdGggdGhlc2UgcXVlcmllcykNCmxhZ29zX25oZF8yIDwtIGxhZ29zX2RmICU+JQ0KICBtdXRhdGUoT2xkUmVhY2hDb2RlID0gUmVhY2hDb2RlKSAlPiUgIyB0aW5rZXJpbmcgZm9yIHVwY29taW5nIHVuaW9uDQogIGZpbHRlcighaXMubmEoUmVhY2hDb2RlKSkgJT4lDQogIGxlZnRfam9pbihuaGRfcGx1cywgYnkgPSBjKCJSZWFjaENvZGUiID0gIlJFQUNIQ09ERSIpLCBzdWZmaXggPSBjKCJfSFIiLCAiX01SIikpDQoNCmxhZ29zX25oZF9hbGwgPC0gbGFnb3NfbmhkXzEgJT4lDQogIHNlbGVjdCgtT2xkUmVhY2hEYXRlLCAtTmV3UmVhY2hEYXRlKSAlPiUNCiAgdW5pb24obGFnb3NfbmhkXzIpDQpgYGANCg0KTnVtZXJvdXMgbGFrZXMgYXJlbid0IGFibGUgdG8gYmUgY29ubmVjdGVkIGJldHdlZW4gdGhlIE5IRFBsdXNWMiBhbmQgdGhlIE5IRCBIUi4gVGhlIEhSIGNvbnRhaW5zIG1vcmUgc21hbGwgbGFrZXMsIHNvIGxldCdzIGxvb2sgZm9yIGEgbWludXRlIG9ubHkgYXQgbGFrZXMgb3ZlciAxMCBoZWN0YXJlcy4gSGVyZSBhcmUgYSBmZXcgZXhhbXBsZXMgb2YgbGFrZXMgd2hlcmUgdGhlIG9sZCByZWFjaCBjb2RlcyBhcmUgdW5hdmFpbGFibGUgb3Igbm90IHRoZSB0YXJnZXQgcmVhY2ggY29kZS4NCmBgYHtyIGpvaW4tbmhkM30NCiMgZXhhbXBsZXNbMV06IFNpbXBseSBubyBjb25uZWN0aW9uIGJldHdlZW4gY29kZXMuIEZvcm1lciBjb2RlIGlzIDAxMDkwMDAxMDMxMDEwLg0KIyBleGFtcGxlc1syXTogT25lIGxha2UgdG8gdGhyZWUuIEZpcnN0IGxha2Uga2VlcHMgcmVhY2ggY29kZSwgb3RoZXIgdHdvIGFyZW4ndCBsaW5rZWQgKDAxMDkwMDAzMDAwOTE4LCAwMTA5MDAwMzAwODA3NikNCiMgZXhhbXBsZXNbM106IFRocmVlIGxha2VzIHRvIG9uZS4gTmV3IGNvZGUgZW50ZXJlZCBhcyB1bmxpbmtlZC4gT2xkIHRocmVlIGNvZGVzIG5ldmVyIGFwcGVhciBpbiB0aGUgdGFibGUgKHRoZXkgd2VyZSBkcm9wcGVkIG9uY2UgZGVsZXRlZCkuIFRob3NlIGNvZGVzIGFyZQ0KIyAwMjAzMDEwNDAwMDQ3MCwgMDIwMzAxMDQwMDA0NzMsIDAyMDMwMTA0MDAwNDY4DQpleGFtcGxlcyA8LSBjKCcwMTA5MDAwMTAwMTYzNCcsICcwMTA5MDAwMzAwODA3NScsICcwMjAzMDEwNDAwNTI1MScpDQoNCm5vX2xpbmsgPC0gbGFnb3NfbmhkX2FsbCAlPiUNCiAgZmlsdGVyKEFyZWFTcUttID49IC4xKSAlPiUNCiAgZ3JvdXBfYnkobGFnb3NsYWtlaWQsIFJlYWNoQ29kZSkgJT4lDQogIHN1bW1hcml6ZShuID0gbl9kaXN0aW5jdChDT01JRCwgbmEucm0gPSBUUlVFKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZmlsdGVyKG4gPCAxKQ0KDQpub19saW5rX2FsbCA8LSBsYWdvc19uaGRfYWxsICU+JQ0KICAjIHNhbWUgYXMgYWJvdmUgZXhjZXB0IHRoaXMgZmlsdGVyIHN0ZXANCiAgZ3JvdXBfYnkobGFnb3NsYWtlaWQsIFJlYWNoQ29kZSkgJT4lDQogIHN1bW1hcml6ZShuID0gbl9kaXN0aW5jdChDT01JRCwgbmEucm0gPSBUUlVFKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZmlsdGVyKG4gPCAxKQ0KDQooZGlzcGxheSA8LSBuaGRfeHJlZiAlPiUNCiAgZmlsdGVyKE9sZFJlYWNoQ29kZSAlaW4lIGV4YW1wbGVzIHwgTmV3UmVhY2hDb2RlICVpbiUgZXhhbXBsZXMpICU+JQ0KICBtdXRhdGUoT2xkUmVhY2hDb2RlID0gYXMuY2hhcmFjdGVyKE9sZFJlYWNoQ29kZSksIE5ld1JlYWNoQ29kZSA9IGFzLmNoYXJhY3RlcihOZXdSZWFjaENvZGUpKSAlPiUNCiAgICBhcnJhbmdlKE5ld1JlYWNoQ29kZSkpDQpgYGANCg0KRm9yIHRob3NlIGxha2VzIHRoYXQgZGlkbid0IGxpbmsgYmV0d2VlbiBOSEQgdmVyc2lvbnMsIHRyeSBsaW5raW5nIHRoZW0gdGhyb3VnaCBHTklTIElEcy4NCmBgYHtyIGpvaW4tbmhkNH0NCm5oZF9nbmlzX25oZCA8LSBsYWdvc19kZiAlPiUNCiAgaW5uZXJfam9pbihub19saW5rX2FsbCkgJT4lDQogIGZpbHRlcighaXMubmEoR05JU19JRCkpICU+JQ0KICBpbm5lcl9qb2luKG5oZF9wbHVzLCBieSA9IGMoIkdOSVNfSUQiID0gIkdOSVNfSUQiKSkNCmBgYA0KSXQgd29ya3MuICoqYHIgbnJvdyhuaGRfZ25pc19uaGQpYCoqIGxha2VzIHRoYXQgY291bGRuJ3QgYmUgbGlua2VkIHdpdGggTkhEUmVhY2hDcm9zc1JlZmVyZW5jZSBjYW4gYmUgbGlua2VkIHdpdGggdGhlIEdOSVNfSUQgdmFsdWUuDQoNCiMjIFNlbGVjdCBhZ2Fpbg0KYGBge3Igc2VsZWN0Mi1uaGQsIGVjaG8gPSBUUlVFfQ0KbGFnb3NfbmhkX25vdF9taXNzaW5nIDwtIGxhZ29zX25oZF9hbGwgJT4lDQogIGZpbHRlcighaXMubmEoQ09NSUQpKQ0KDQpsYWdvc19uaGQgPC0gbGFnb3NfZGYgJT4lDQogIGxlZnRfam9pbihsYWdvc19uaGRfbm90X21pc3NpbmcsIGJ5ID0gImxhZ29zbGFrZWlkIikgJT4lICMgcmVtb3ZlcyBPbGRSZWFjaENvZGVzIHRoYXQgZG9uJ3QgbGluayBidXQga2VlcHMgYWxsIGxha2VzDQogIGxlZnRfam9pbihuaGRfZ25pc19uaGQsIGJ5ID0gImxhZ29zbGFrZWlkIikgJT4lDQogIG11dGF0ZShOSERQbHVzdjJfQ09NSUQgPSBjb2FsZXNjZShDT01JRC54LCBDT01JRC55KSkgJT4lDQogIG11dGF0ZShOSERQbHVzdjJfUmVhY2hDb2RlID0gY29hbGVzY2UoT2xkUmVhY2hDb2RlLCBSRUFDSENPREUpKSAlPiUNCiAgbXV0YXRlKE5IRFBsdXN2Ml9HTklTX05hbWUgPSBjb2FsZXNjZShHTklTX05BTUUueCwgR05JU19OQU1FLnkpKSAlPiUgI2FsbC1jYXBzIGlzIG1lZGl1bSByZXMNCiAgbXV0YXRlKE5IRFBsdXN2Ml9BcmVhU3FLbSA9IGNvYWxlc2NlKEFSRUFTUUtNLngsIEFSRUFTUUtNLnkpKSAlPiUNCiAgc2VsZWN0KGxhZ29zbGFrZWlkLCBOSERQbHVzdjJfQ09NSUQsIE5IRFBsdXN2Ml9SZWFjaENvZGUsIE5IRFBsdXN2Ml9HTklTX05hbWUsIE5IRFBsdXN2Ml9BcmVhU3FLbSkNCmBgYA0KDQojIExBR09TLU5FDQpMQUdPUy1ORSB3YXMgdGhlIGZpcnN0IHJlbGVhc2UgZnJvbSB0aGUgTEFHT1MgcHJvamVjdCBkZXNjcmliaW5nIGxha2VzIGluIDE3IHN0YXRlcyBpbiB0aGUgbm9ydGhlYXN0ZXJuIHN0YXRlcy4gSXQgaXMgc2ltaWxhciBpbiBtb3N0IHdheXMgdG8gTEFHT1MtVVMsIGJ1dCB0aGUgTkhEIHNuYXBzaG90cyB3ZXJlIHRha2VuIHNldmVyYWwgeWVhcnMgYWdvLiBUaGlzIGRhdGFzZXQgY2FuIGJlIGRvd25sb2FkZWQgYW5kIHVuemlwcGVkIGZyb20gW2h0dHBzOi8vcG9ydGFsLmVkaXJlcG9zaXRvcnkub3JnL25pcy9tYXBicm93c2U/cGFja2FnZWlkPWVkaS45OC4xXS4NCg0KV2hlbiB0aGUgTEFHT1MtVVMgbGFnb3NsYWtlaWQgdmFsdWVzIHdlcmUgZ2VuZXJhdGVkLCB0aGV5IHdlcmUgam9pbmVkIG9uIFBlcm1hbmVudF9JZGVudGlmaWVyIHRvIHRoZSBMQUdPUy1ORSwgc28gbW9zdCBvZiB0aGUgbGFnb3NsYWtlaWQgdmFsdWVzIHNob3VsZCBub3QgaGF2ZSBjaGFuZ2VkLiBOb25ldGhlbGVzcywgc29tZSBjb3VsZCBub3QgYmUgY29ubmVjdGVkIHRoaXMgd2F5Lg0KDQojIyBJbXBvcnQNCkdsaW1wc2UgdGhlIG9yaWdpbmFsIExBR09TLU5FIGRhdGFzZXQuDQpgYGB7ciByZWFkLW5lfQ0KIyBsYWdvc05FX29yaWcgPC0gc3RfcmVhZCgnQzovVXNlcnMvc21pdGhuNzgvRHJvcGJveC9DU0kvQ1NJX0xBR09TLWV4cG9ydHMvTEFHT1MtTkUtRURJL0xBR09TLU5FLUdJUy9GaWxlR0RCL0xBR09TX05FX0dJU19EYXRhX3YxLjAuZ2RiJywgJ0xBR09TX05FX0FsbF9MYWtlc18xaGEnKSAlPiUNCiMgICBzdF96bShkcm9wPVRSVUUpICU+JQ0KIyAgIG11dGF0ZShHTklTX0lEID0gYXMubnVtZXJpYyhHTklTX0lEKSkgJT4lDQojICAgc3RfdHJhbnNmb3JtKEFMQkVSU19VU0dTKSAjIG5vIGFjdHVhbCBjaGFuZ2UsIGp1c3QgcHJvajRzdHJpbmcgaG91c2VrZWVwaW5nLg0KIyBzYXZlKGxhZ29zTkVfb3JpZywgZmlsZSA9ICcuL3JkYXRhL2xhZ29zTkVfb3JpZy5SRGF0YScpDQpsb2FkKCcuL3JkYXRhL2xhZ29zTkVfb3JpZy5SRGF0YScpDQpnbGltcHNlKGxhZ29zTkVfb3JpZywgd2lkdGggPSAxMDApDQpgYGANCg0KIyMgRmlsdGVyDQpObyBuZWVkIHRvIGZpbHRlci4gVGhlc2UgbGFrZXMgaGFkIGVzc2VudGlhbGx5IHRoZSBzYW1lIGNyaXRlcmlhIGZvciBpbmNsdXNpb24gYXMgTEFHTy1VUywgYWJvdmUsIGV4Y2VwdCB0aGF0IHRoZXkgd2VyZSBjb25maW5lZCB0byBhIDE3LXN0YXRlIHJlZ2lvbiBpbiB0aGUgbm9ydGhlYXN0IFUuUy4NCg0KIyMgQ29udmVydCBhbmQgc2VsZWN0DQpgYGB7ciBjb252ZXJ0LW5lLCBlY2hvID0gVFJVRX0NCmxhZ29zTkUgPC0gbGFnb3NORV9vcmlnICU+JQ0KICBzZWxlY3QoTEFHT1NORV9sYWdvc2xha2VpZCA9IGxhZ29zbGFrZWlkLCBMQUdPU05FX1Blcm1hbmVudElkZW50aWZpZXIgPSBQZXJtYW5lbnRfSWRlbnRpZmllciwgTEFHT1NORV9SZWFjaENvZGUgPSBSZWFjaENvZGUsIEdOSVNfSUQsIEdOSVNfTmFtZSkgJT4lDQogIHN0X3NldF9nZW9tZXRyeShOVUxMKQ0KYGBgDQoNCiMjIEpvaW4gTEFHT1MtVVMNClVubGlrZSB3aXRoIE5IRFBsdXNWMiwgdGhlc2UgdHdvIGRhdGFzZXRzIHNoYXJlZCB0aGUgaWRlbnRpZmllciBQZXJtYW5lbnRfSWRlbnRpZmllciBhbmQgd2Ugd2lsbCB0cnkgdG8gam9pbiBsYWtlcyBvbiB0aGF0IGNvbHVtbiBmaXJzdC4gVGhlIHN1YnNlcXVlbnQgdHdvIGpvaW5zIHBhcmFsbGVsIHRoZSBqb2lucyB3aXRoIE5IRFBsdXNWMiwgYWJvdmUuIFdlIHdpbGwgcmV1c2UgdGhlIGxhZ29zX25oZHggdGFibGUuDQpgYGB7ciBqb2luLW5lMH0NCmxhZ29zX2xhZ29zTkVfMCA8LSBsYWdvc19kZiAlPiUNCiAgaW5uZXJfam9pbihsYWdvc05FLCBieSA9IGMoIlBlcm1hbmVudF9JZGVudGlmaWVyIiA9ICJMQUdPU05FX1Blcm1hbmVudElkZW50aWZpZXIiKSwgc3VmZml4ID0gYygiX1VTIiwgIl9ORSIpKSAlPiUNCiAgcmVuYW1lKE9sZFJlYWNoQ29kZSA9IExBR09TTkVfUmVhY2hDb2RlKSAlPiUNCiAgbXV0YXRlKExBR09TTkVfUGVybWFuZW50SWRlbnRpZmllciA9IFBlcm1hbmVudF9JZGVudGlmaWVyKQ0KDQpgYGANCg0KDQpgYGB7ciBqb2luLW5lMX0NCmxhZ29zX2xhZ29zTkVfMSA8LSBsYWdvc19uaGR4ICU+JQ0KICBmaWx0ZXIoIWlzLm5hKE9sZFJlYWNoQ29kZSkpICU+JQ0KICBsZWZ0X2pvaW4obGFnb3NORSwgYnkgPSBjKCJPbGRSZWFjaENvZGUiID0gIkxBR09TTkVfUmVhY2hDb2RlIiksIHN1ZmZpeCA9IGMoIl9VUyIsICJfTkUiKSkNCg0KIyBKb2luIG9uIG5ldyByZWFjaCBjb2RlcyAoYWJvdXQgYSBkb3plbiBsYWtlcyB3aWxsIGxpbmsgaW4gYm90aCB0aGVzZSBxdWVyaWVzKQ0KbGFnb3NfbGFnb3NORV8yIDwtIGxhZ29zX2RmICU+JQ0KICBtdXRhdGUoT2xkUmVhY2hDb2RlID0gUmVhY2hDb2RlKSAlPiUgIyB0aW5rZXJpbmcgZm9yIHVwY29taW5nIHVuaW9uDQogIGZpbHRlcighaXMubmEoUmVhY2hDb2RlKSkgJT4lDQogIGxlZnRfam9pbihsYWdvc05FLCBieSA9IGMoIlJlYWNoQ29kZSIgPSAiTEFHT1NORV9SZWFjaENvZGUiKSwgc3VmZml4ID0gYygiX1VTIiwgIl9ORSIpKQ0KDQpsYWdvc19sYWdvc05FX2FsbCA8LSBsYWdvc19sYWdvc05FXzEgJT4lDQogIHNlbGVjdCgtT2xkUmVhY2hEYXRlLCAtTmV3UmVhY2hEYXRlKSAlPiUNCiAgdW5pb24obGFnb3NfbGFnb3NORV8yKSAlPiUgDQogIHVuaW9uKGxhZ29zX2xhZ29zTkVfMCkNCmBgYA0KDQpBZnRlciB0cnlpbmcgdGhlIGNvZGUgYmVsb3cgKGN1cnJlbnRseSBjb21tZW50ZWQgb3V0KSwgaXQgc2VlbXMgdXBvbiBmdXJ0aGVyIG9ic2VydmF0aW9uIHRoYXQgdGhlIEdOSVNfSUQgdmFsdWVzIGluIExBR09TLU5FIGhhdmUgbm8gdXNlZnVsIHJlbGF0aW9uIHRvIHRoZSBsYXRlc3QgR05JU19JRCB2YWx1ZXMuIA0KYGBge3Igam9pbi1uZTJ9DQojIG5vX2xpbmtfbGFnb3NORSA8LSBsYWdvc19sYWdvc05FX2FsbCAlPiUNCiMgICBncm91cF9ieShsYWdvc2xha2VpZCwgUmVhY2hDb2RlKSAlPiUNCiMgICBzdW1tYXJpemUobiA9IG5fZGlzdGluY3QoTEFHT1NORV9sYWdvc2xha2VpZCwgbmEucm0gPSBUUlVFKSkgJT4lDQojICAgdW5ncm91cCgpICU+JQ0KIyAgIGZpbHRlcihuIDwgMSkNCiMgDQojIGxhZ29zVVNfZ25pc19sYWdvc05FIDwtIGxhZ29zX2RmICU+JQ0KIyAgIGlubmVyX2pvaW4obm9fbGlua19sYWdvc05FKSAlPiUNCiMgICBmaWx0ZXIoIWlzLm5hKEdOSVNfSUQpKSAlPiUNCiMgICBpbm5lcl9qb2luKGxhZ29zTkUsIGJ5ID0gYygiR05JU19JRCIgPSAiR05JU19JRCIpKQ0KYGBgDQoNCg0KIyMgU2VsZWN0IGFnYWluDQpgYGB7ciBzZWxlY3QyLW5lLCBlY2hvID0gVFJVRX0NCmxhZ29zVVNfbGFnb3NORSA8LSBsYWdvc19sYWdvc05FX2FsbCAlPiUNCiAgZmlsdGVyKCFpcy5uYShMQUdPU05FX2xhZ29zbGFrZWlkKSkgJT4lDQogIGFycmFuZ2UobGFnb3NsYWtlaWQpDQpgYGANCg0KIyBOTEEgKFVTIEVQQSBOYXRpb25hbCBMYWtlcyBBc3Nlc3NtZW50KQ0KVGhlIGxha2VzIGluIHRoZSBOTEEgYXJlIGlkZW50aWZpZWQgd2l0aCB0aGVpciBOSERQbHVzIENPTUlEIGFuZCBSZWFjaENvZGUuIEl0ICpzaG91bGQqIGJlIHNpbXBsZSB0byBhZGQgdGhlbSB0byB0aGUgY3Jvc3N3YWxrIGJ5IGRvaW5nIGEgMToxIGpvaW4gd2l0aCB0aGUgTkhEUGx1c1YyIENPTUlELg0KDQojIyBJbXBvcnQNCkltcG9ydCB0aGUgdHdvIE5MQSBmaWxlcy4gSXQgc2VlbXMgdGhhdCB0aGUgMjAxMiBmaWxlIGFscmVhZHkgbWFuYWdlcyB0aGUgbGluayBiZXR3ZWVuIHRoZSAyMDEyIHNpdGVzIGJhY2sgdG8gdGhlIDIwMDcgc2l0ZXMuDQpgYGB7cn0NCm5sYTIwMDdfb3JpZyA8LSByZWFkX2NzdignaHR0cHM6Ly93d3cuZXBhLmdvdi9zaXRlcy9wcm9kdWN0aW9uL2ZpbGVzLzIwMTQtMDEvbmxhMjAwN19zYW1wbGVkbGFrZWluZm9ybWF0aW9uXzIwMDkxMTEzLmNzdicsDQogICAgICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyhSRUFDSENPREUgPSBjb2xfY2hhcmFjdGVyKCkpKQ0KbmxhMjAxMl9vcmlnIDwtIHJlYWRfY3N2KCdodHRwczovL3d3dy5lcGEuZ292L3NpdGVzL3Byb2R1Y3Rpb24vZmlsZXMvMjAxNi0xMi9ubGEyMDEyX3dpZGVfc2l0ZWluZm9fMDgyMzIwMTYuY3N2JywNCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSBjb2xzKFJDSENPREUgPSBjb2xfY2hhcmFjdGVyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBORVNMQUtFX0lEID0gY29sX2NoYXJhY3RlcigpKSkgIyB1bmltcG9ydGFudCBidXQgYXZvaWQgaW1wb3J0IGVycm9yKSkNCg0KZ2xpbXBzZShubGEyMDEyX29yaWcsIHdpZHRoID0gMTAwKQ0KYGBgDQoNClVuZm9ydHVuYXRlbHksIHRoZSBSQ0hDT0RFIHZhbHVlcyBpbiB0aGUgMjAxMiBkYXRhIHRoYXQgY2FuIGJlIGRvd25sb2FkZWQgb25saW5lIHdlcmUgZXhwb3J0ZWQgaW1wcm9wZXJseSwgdXNpbmcgc2NpZW50aWZpYyBub3RhdGlvbiB0aGF0IGN1dHMgb2ZmIHRoZSB2ZXJ5IGltcG9ydGFudCBmaW5hbCBkaWdpdHMuIEZvciBleGFtcGxlOg0KYGBge3J9DQpubGEyMDEyX29yaWcgJT4lIHNlbGVjdChSQ0hDT0RFKSAlPiUgc2FtcGxlX24oMTApDQpgYGANCldpdGggbHVjaywgd2UgY2FuIHdvcmsgYXJvdW5kIHRoaXMgaXNzdWUuDQoNCjwhLS0tVGhpcyBubyBsb25nZXIgc2VlbXMgbmVjZXNzYXJ5OiBJbXBvcnQgdGhlIE5IRFBsdXMgVjEtdG8tVjIgY3Jvc3N3YWxrLi0tLT4NCmBgYHtyfQ0KIyAjICMgQ29kZSBmb3IgcmVwcm9kdWNpYmlsaXR5LCByZXF1aXJlcyBkZXZ0b29scyBhbmQgcGFja2FnZSAiYXJjaGl2ZSIgb24gR2l0aHViDQojICMgaWYoIXJlcXVpcmUoImFyY2hpdmUpIikpIHsNCiMgIyAgIGlmKCFyZXF1aXJlKCJkZXZ0b29scyIpKSBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpDQojICMgICBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImppbWhlc3Rlci9hcmNoaXZlIikNCiMgIyB9DQojICMgaWYoIXJlcXVpcmUoImZvcmVpZ24iKSkgaW5zdGFsbC5wYWNrYWdlcygiZm9yZWlnbiIpDQojICMgdGYgPC0gdGVtcGZpbGUoKQ0KIyAjIGRvd25sb2FkLmZpbGUoJ2h0dHA6Ly93d3cuaG9yaXpvbi1zeXN0ZW1zLmNvbS9OSERQbHVzRGF0YS9OSERQbHVzVjIxL0RhdGEvTmF0aW9uYWxEYXRhL05IRFBsdXNWMjFfTmF0aW9uYWxEYXRhX1YxX1RvX1YyX0Nyb3Nzd2Fsa18wMS43eicsIHRmLCBtb2RlID0gJ3diJykNCiMgIyBkYmZfcGF0aCA8LSBhcmNoaXZlOjphcmNoaXZlX2V4dHJhY3QodGYsICcuJywgJ05IRFBsdXNWMU5ldHdvcmtfVjJOZXR3b3JrX0Nyb3Nzd2Fsay5kYmYnKSRwYXRoWzFdDQojICMgdjFfdjJfeHdhbGsgPC0gZm9yZWlnbjo6cmVhZC5kYmYoZGJmX3BhdGhbMV0pDQojICMgdW5saW5rKHRmKQ0KIyAjIHNhdmUodjFfdjJfeHdhbGssIGZpbGUgPSAnLi9yZGF0YS92MV92Ml94d2Fsay5SRGF0YScpDQojIGxvYWQoJy4vcmRhdGEvdjFfdjJfeHdhbGsuUkRhdGEnKQ0KIyBnbGltcHNlKHYxX3YyX3h3YWxrKQ0KYGBgDQoNCiMjIEZpbHRlcg0KTm8gbmVlZC4NCg0KIyMgQ29udmVydA0KTm8gbmVlZC4NCg0KIyMgU2VsZWN0DQpgYGB7ciwgZWNobyA9IFRSVUV9DQpubGEyMDA3IDwtIG5sYTIwMDdfb3JpZyAlPiUNCiAgZGlzdGluY3QoU0lURV9JRCwgUkVBQ0hDT0RFLCBDT01fSUQpDQoNCm5sYTIwMTIgPC0gbmxhMjAxMl9vcmlnICU+JQ0KICBkaXN0aW5jdChTSVRFX0lELCBTSVRFSURfMDcsIENPTUlEMjAxMiwgQ09NSUQyMDA3LCBDT01JRFMyMDA3LCBHTklTX0lELCBHTklTX05BTUUsIE5FU1NUT1JFVCkNCmBgYA0KDQojIyBKb2luIHRvIExBR09TX1VTIHZpYSBOSERQbHVzVjIgdmlhIHRoZSBWMS10by1WMiBjcm9zc3dhbGsuDQpXZSB3aWxsIHVzZSB0aGUgbmxhMjAxMiB0YWJsZSBhcyB0aGUgbGVmdCB0YWJsZSBpbiB0aGUgam9pbiBhbmQgYWxzbyBqb2luIHRocm91Z2ggdGhlIG9yaWdpbmFsIG5oZF9wbHVzIGRhdGFzZXQgc28gdGhhdCB3ZSBjYW4gcHJvZHVjZSBhIGxpc3Qgb2YgTkxBIGxha2VzIHRoYXQgY291bGQgbm90IGJlIGxpbmtlZCB0byBhIGxhZ29zbGFrZWlkLiBUaGUgTkxBIGxha2VzIHRoYXQgZG9uJ3QgbGluayB3aWxsIGJlIGFzc2lnbmVkIGEgbGFnb3NsYWtlaWQgdGhyb3VnaCBvdXIgbWFudWFsIGxpbmtpbmcgcHJvY2VzcyAodGhhdCBzdGFydHMgd2l0aCBhIHNwYXRpYWwgbGluaykuDQpgYGB7cn0NCm5sYTIwMTJfbGFnb3Nfam9pbiA8LSBubGEyMDEyICU+JQ0KICBsZWZ0X2pvaW4obmhkX3BsdXMsIGJ5ID0gYygiQ09NSUQyMDEyIiA9ICJDT01JRCIpKSAlPiUNCiAgbGVmdF9qb2luKGxhZ29zX25oZCwgYnkgPSBjKCJDT01JRDIwMTIiID0gIk5IRFBsdXN2Ml9DT01JRCIpKQ0KYGBgDQoNCkNoZWNrIG9uIGhvdyBtYW55IGxha2VzIGRpZG4ndCBsaW5rIHRocm91Z2ggZWFjaCBzdGVwLg0KYGBge3J9DQpuX25sYV9uaGQgPC0gbmxhMjAxMl9sYWdvc19qb2luICU+JQ0KICBmaWx0ZXIoaXMubmEoUkVBQ0hDT0RFKSkgJT4lDQogIGRpc3RpbmN0KFNJVEVfSUQpICU+JQ0KICBucm93KCkNCm5fbmxhX2xhZ29zIDwtIG5sYTIwMTJfbGFnb3Nfam9pbiAlPiUNCiAgZmlsdGVyKGlzLm5hKGxhZ29zbGFrZWlkKSkgJT4lDQogIGRpc3RpbmN0KFNJVEVfSUQpICU+JQ0KICBucm93KCkNCmBgYA0KKipgciBuX25sYV9uaGRgKiogbGFrZXMgb3V0IG9mICoqYHIgbnJvdyhubGEyMDEyKWAqKiBOTEEgbGFrZXMgY2Fubm90IGJlIGxpbmtlZCB0byB0aGUgTkhEUGx1c1YyLiBXZSBkaWQgdHJ5IHRoZSBWMS10by1WMiBjcm9zc3dhbGsgYW5kIHdlcmUgbm90IGFibGUgdG8gbWFrZSBhbnkgYWRkaXRpb25hbCBsaW5rcy4gRmFyIG1vcmUgbGFrZXMgYXJlIHVuYWJsZSB0byBiZSBsaW5rZWQgdG8gYSBsYWdvc2xha2VpZDogKipgciBuX25sYV9sYWdvc2AqKi4gVGhpcyBpcyBkdWUgdG8gdGhlIHBvb3IgbWF0Y2ggYmV0d2VlbiB0aGUgTkhEUGx1c1YyIGFuZCB0aGUgTEFHT1MgTGFrZSBwb3B1bGF0aW9uLiBJZiB3ZSBpbXByb3ZlIHRoYXQgbGluaywgdGhlc2UgbnVtYmVycyB3aWxsIGluY3JlYXNlLiBUaGlzIHdvcmsgaXMgcHJvcG9zZWQuDQoNCiMjIFNlbGVjdCBhZ2Fpbg0KU2VsZWN0IDIgY29sdW1ucyBmcm9tIHRoZSBOTEEgMjAxMiBhbmQgbGFnb3NsYWtlaWQuDQpgYGB7ciwgZWNobyA9IFRSVUV9DQpubGEyMDEyX2xhZ29zIDwtIG5sYTIwMTJfbGFnb3Nfam9pbiAlPiUNCiAgc2VsZWN0KA0KICAgIE5MQTIwMTJfU0lURV9JRCA9IFNJVEVfSUQsDQogICAgTkxBMjAwN19TSVRFX0lEID0gU0lURUlEXzA3LA0KICAgIGxhZ29zbGFrZWlkDQogICkNCmBgYA0KDQoNCiMgRmluYWwsIHNpbmdsZSBjcm9zc3dhbGsgdGFibGUNCkZvciB0aGUgZmluYWwgdGFibGUsIHdlJ2xsIGpvaW4gYWxsIHRoZSBwcmV2aW91cyByZXN1bHRzIHRvZ2V0aGVyIHdpdGggdGhlIGVudGlyZSBMQUdPUy1VUyBsYWtlIHBvcHVsYXRpb24gb24gdGhlIGxlZnQgc2lkZSBvZiB0aGUgam9pbi4gVGhlbiwgaW4gb3JkZXIgdG8gZmFjaWxpdGF0ZSBhIHVzZXIgdW5kZXJzdGFuZGluZyBvZiAxLXRvLW1hbnkgcmVsYXRpb25zaGlwcyBpbiB0aGUgdGFibGUsIHdlIHdpbGwgZ2VuZXJhdGUgc29tZSBjb3VudCBjb2x1bW5zIHRoYXQgaW5kaWNhdGUgd2hlbiBtdWx0aXBsZSBpZGVudGlmaWVycyBpbiBvbmUgZGF0YXNldCByZWxhdGUgdG8gYSBzaW5nbGUgaWRlbnRpZmllciBpbiBhbm90aGVyLiBGaW5hbGx5LCB3ZSB3aWxsIGRvIHRoZSBmaW5hbCBzZWxlY3Rpb24gb2YgY29sdW1ucyBmb3IgdGhlIG91dHB1dCBhbmQgcmVuYW1lIGEgZmV3IG1vcmUgY29sdW1ucyB0byBtYXRjaCB0aGUgbmFtaW5nIHRlbXBsYXRlLg0KYGBge3IgZmluYWx9DQojIHN0YXJ0IHdpdGggbGFnb3MgYmFzZWQgc3R1ZmYNCnRvZ2V0aGVyIDwtIGxhZ29zX2duaXMgJT4lDQogIGlubmVyX2pvaW4obGFnb3NfY2VudHJvaWQsIGJ5ID0gImxhZ29zbGFrZWlkIikgJT4lDQogIGxlZnRfam9pbihsYWdvc193cXAsIGJ5ID0gYygibGFnb3NsYWtlaWQiID0gIkxpbmtlZF9sYWdvc2xha2VpZCIpKSAlPiUNCiAgbGVmdF9qb2luKGxhZ29zX25oZCwgYnkgPSAibGFnb3NsYWtlaWQiKSAlPiUNCiAgbGVmdF9qb2luKGxhZ29zVVNfbGFnb3NORSwgYnkgPSAibGFnb3NsYWtlaWQiKSAlPiUNCiAgbGVmdF9qb2luKG5sYTIwMTJfbGFnb3MsIGJ5ID0gImxhZ29zbGFrZWlkIikNCg0KDQoNCmNvdW50c19yb3VuZDEgPC0gdG9nZXRoZXIgJT4lDQogIGdyb3VwX2J5KGxhZ29zbGFrZWlkKSAlPiUNCiAgc3VtbWFyaXplKGNvdW50X3dxcF9wZXJfbGFnb3NfaWQgPSBuX2Rpc3RpbmN0KE1vbml0b3JpbmdMb2NhdGlvbklkZW50aWZpZXIsIG5hLnJtID0gVFJVRSksIA0KICAgICAgICAgICAgY291bnRfbmhkcGx1c3YyX3Blcl9sYWdvc19pZCA9IG5fZGlzdGluY3QoTkhEUGx1c3YyX0NPTUlELCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgY291bnRfbGFnb3NORV9wZXJfbGFnb3NfaWQgPSBuX2Rpc3RpbmN0KExBR09TTkVfbGFnb3NsYWtlaWQsIG5hLnJtID0gVFJVRSkpICU+JQ0KICByaWdodF9qb2luKHRvZ2V0aGVyLCBieSA9ICJsYWdvc2xha2VpZCIpDQoNCmNvdW50c19yb3VuZDIgPC0gY291bnRzX3JvdW5kMSAlPiUNCiAgZmlsdGVyKCFpcy5uYShOSERQbHVzdjJfQ09NSUQpKSAlPiUNCiAgZ3JvdXBfYnkoTkhEUGx1c3YyX0NPTUlEKSAlPiUNCiAgc3VtbWFyaXplKGNvdW50X2xhZ29zX3Blcl9uaGRwbHVzdjJfaWQgPSBuX2Rpc3RpbmN0KGxhZ29zbGFrZWlkLCBuYS5ybSA9IFRSVUUpKSU+JQ0KICByaWdodF9qb2luKGNvdW50c19yb3VuZDEsIGJ5ID0gIk5IRFBsdXN2Ml9DT01JRCIpDQoNCmNvdW50c19yb3VuZDMgPC0gY291bnRzX3JvdW5kMiAlPiUNCiAgZmlsdGVyKCFpcy5uYShMQUdPU05FX2xhZ29zbGFrZWlkKSkgJT4lDQogIGdyb3VwX2J5KExBR09TTkVfbGFnb3NsYWtlaWQpICU+JQ0KICBzdW1tYXJpemUoY291bnRfbGFnb3NfcGVyX2xhZ29zTkVfaWQgPSBuX2Rpc3RpbmN0KGxhZ29zbGFrZWlkLCBuYS5ybSA9IFRSVUUpKSU+JQ0KICByaWdodF9qb2luKGNvdW50c19yb3VuZDIsIGJ5ID0gIkxBR09TTkVfbGFnb3NsYWtlaWQiKQ0KDQpmaW5hbCA8LSBjb3VudHNfcm91bmQzICU+JQ0KICBzZWxlY3QoDQogICAgbGFnb3NsYWtlaWQsDQogICAgTkhESFJfUGVybWFuZW50SWRlbnRpZmllciA9IFBlcm1hbmVudF9JZGVudGlmaWVyLngsDQogICAgTkhESFJfUmVhY2hDb2RlID0gUmVhY2hDb2RlLngsDQogICAgTkhESFJfQXJlYVNxS20gPSBBcmVhU3FLbS54LA0KICAgIEdOSVNfSUQsDQogICAgR05JU19OYW1lLA0KICAgIExBR09TX0xha2VOYW1lLA0KICAgIExBR09TX0NvdW50eU5hbWUsDQogICAgTEFHT1NfQ291bnR5RklQUywNCiAgICBMQUdPU19MYXRpdHVkZU5BRDgzLA0KICAgIExBR09TX0xvbmdpdHVkZU5BRDgzLA0KICAgIFN0YXRlID0gU1RBVEUueCwNCiAgICBXUVBfTW9uaXRvcmluZ0xvY2F0aW9uSWRlbnRpZmllciA9IE1vbml0b3JpbmdMb2NhdGlvbklkZW50aWZpZXIsDQogICAgV1FQX01vbml0b3JpbmdMb2NhdGlvbk5hbWUgPSBNb25pdG9yaW5nTG9jYXRpb25OYW1lLA0KICAgIFdRUF9Qcm92aWRlck5hbWUgPSBQcm92aWRlck5hbWUsDQogICAgTkhEUGx1c3YyX0NPTUlELA0KICAgIE5IRFBsdXN2Ml9SZWFjaENvZGUsDQogICAgTkhEUGx1c3YyX0FyZWFTcUttLA0KICAgIExBR09TTkVfbGFnb3NsYWtlaWQsDQogICAgTkxBMjAwN19TSVRFX0lELA0KICAgIE5MQTIwMTJfU0lURV9JRCwNCiAgICBjb3VudF93cXBfcGVyX2xhZ29zX2lkLA0KICAgIGNvdW50X25oZHBsdXN2Ml9wZXJfbGFnb3NfaWQsDQogICAgY291bnRfbGFnb3NfcGVyX25oZHBsdXN2Ml9pZCwNCiAgICBjb3VudF9sYWdvc05FX3Blcl9sYWdvc19pZCwNCiAgICBjb3VudF9sYWdvc19wZXJfbGFnb3NORV9pZA0KICApDQpgYGANCg0KR2xpbXBzZSBhdCB0aGUgZmluYWwgdGFibGUuDQpgYGB7cn0NCmdsaW1wc2UoZmluYWwsIHdpZHRoID0gMTAwKQ0KYGBgDQoNCkFuIGV4YW1wbGUgb2YgYSAgZ3JvdXAgb2YgbGFrZXMgaW4gdGhlIGZpbmFsIHRhYmxlLg0KYGBge3J9DQpmaW5hbCAlPiUgZmlsdGVyKGxhZ29zbGFrZWlkICVpbiUgYygxMCw5LDMzMDk5KSkNCmBgYA0KDQoNCldyaXRlIG91dCB0aGUgZmluYWwgcHJvZHVjdC4NCmBgYHtyIHdyaXRlLWZpbmFsfQ0KI3dyaXRlX2NzdihmaW5hbCwgJ0xBR09TX0xha2VfTGlua192MC5jc3YnKQ0KYGBgDQoNCiMgTGlzdCBvZiB0by1kb3MgYW5kIGlkZWFzIHRvIG1ha2UgbW9yZSBvciBiZXR0ZXIgY29ubmVjdGlvbnMNCkEpIFBST0JMRU06IEFsbW9zdCAyNSUgb2YgbGFrZXMgY2Fubm90IGJlIGxpbmtlZCB0byB0aGVpciBOSERQbHVzdjIgaWRlbnRpZmllciAoYW5kIHRoZXJlZm9yZSB0aGVpciBTdHJlYW1DYXQvTGFrZUNhdCBpZGVudGlmaWVyKS4gU09MVVRJT046IExpbmsgZGlmZmVyaW5nIE5IRCB2ZXJzaW9uIGxha2VzIHRocm91Z2ggc3BhdGlhbCBhbmFseXNpcy4gVGhpcyBpcyB0aGUgaGlnaGVzdCBpbXBhY3Qgc3VnZ2VzdGlvbi4NCkIpIFBST0JMRU06IFRoZXJlIGFyZSBzdGlsbCBtYW55IHVubGlua2VkIFdRUCBzaXRlcyBhbmQgc29tZSBvZiB0aGVtIGRvIGxpbmsgZWFzaWx5IGlmIGFkZXF1YXRlIHJ1bGVzIGFyZSBwcm9wb3NlZCwgYnV0IGludHJvZHVjZSBhIGhpZ2hlciBwb3NzaWJpbGl0eSBvZiBjcmVhdGluZyBpbmNvcnJlY3QgbGlua3MgZm9yIG90aGVyIHNpbWlsYXIgc2l0ZXMuIFNPTFVUSU9OOiBXZSBjb3VsZCBtYWtlIG1vcmUgbGlua3MgdG8gV1FQIHNpdGVzIGlmIHdlIGFkZGVkIGEgd2F5IHRvIGluZGljYXRlICJsb3cgY29uZmlkZW5jZSIgbGlua3MuIEZvciBpbnN0YW5jZTogd2UgY291bGQgYWRkIG1vcmUgc2l0ZXMgdGhhdCBhcmUgd2l0aGluIDEwMCBtIGJ1dCBoYXZlIG5vIG5hbWUgbWF0Y2guDQpDKSBQUk9CTEVNOiBTb21lIGFwcGxpY2F0aW9ucyBhc2sgdXNlcnMgdG8gc3BlY2lmeSB0aGUgbGFrZSB0aGV5J3JlIGF0IHdoZW4gdGhlIHVzZXIgZG9lcyBub3QgaGF2ZSBHUFMgKEV3aW5nIGFuZCBvdGhlcnMgaGFybWZ1bCBhbGdhbCBibG9vbSBhcHApLiBTT0xVVElPTjogQWRkICJuZWFyZXN0IG11bmljaXBhbGl0eSIgdXNpbmcgVElHRVIgZGF0YSBhbmQgYSAiY2xvc2VzdCIgc3BhdGlhbCBqb2luLiAoRGlzY3Vzc2VkIHByZXZpb3VzbHkgd2l0aCBIb2xseSBFd2luZyBhbmQgd2FzIGlkZW50aWZpZWQgYXMgZGVzaXJhYmxlIGF0IHRoaXMgdGltZSwgYnV0IGN1dCBmcm9tIHRoaXMgZHJhZnQgZm9yIHRpbWUuKQ0KRCkgTWFudWFsIGxpbmtzIGZvciBMQUdPUy1ORSBsYWtlcyB0aGF0IGhhdmUgbGltbm8gZGF0YSAoMjYgbGFrZXMpIGJ1dCB0aGF0IGNhbid0IGJlIGZvdW5kIHRocm91Z2ggdGhlIFBlcm1hbmVudF9JZGVudGlmaWVyIG9yIHJlYWNoIGNvZGUgaW4gTEFHT1MtVVMuIChJbiBwcm9ncmVzcykNCkUpIE1hbnVhbCBsaW5rcyBmb3IgYW55IE5MQSBzaXRlcyB0aGF0IHN0aWxsIGRvbid0IGNvbm5lY3QgaWYgd2UgYWRkIHRoZSBzcGF0aWFsIGFuYWx5c2lzIGluIFRPLURPIGl0ZW0gKEIpLg0KRikgTWVyZ2UgTkhEUGx1c1YyIG5hbWVzIGludG8gdGhlIHNlbWktY29sb24gbGlzdCAoY3V0IGZvciB0aW1lLS1uZWVkcyBhbm90aGVyIGpvaW4vZGlzdGluY3QvdmVyYm9zZSBuYW1lIGNhbGN1bGF0aW9uIGNodW5rKQ0KDQojIFRoaW5ncyB0aGF0IGNhbid0IGJlIGRvbmUgd2l0aCB0aGUgY3Jvc3N3YWxrDQpUaGVzZSBpdGVtcyBjYW4gYmUgZGVzY3JpYmVkIGFzIGRlc2lnbmVkIGxpbWl0YXRpb25zIGJlY2F1c2UgdGhpcyBsYWtlIGlkZW50aWZpZXIgY3Jvc3N3YWxrIGlzIGRlc2lnbmVkIHByaW1hcmlseSB0byB3b3JrIHdpdGggTEFHT1MuIE9yLS1pZiB0aGVyZSBpcyBlbm91Z2ggaW50ZXJlc3QgZnJvbSB0aGUgcHJldmlldyBncm91cC0td2UgY2FuIGNvbnNpZGVyIGFkZGluZyB0aGVzZSBjYXBhYmlsaXRpZXMuDQpHKSBBIHVzZXIgY2Fubm90IGZpbmQgaWRlbnRpZmllcnMgcGVydGFpbmluZyB0byBhIGxha2UgdGhhdCBpc24ndCBpbiBMQUdPUy1VUy4gU09MVVRJT046IFVzZSBvdXRlciBqb2lucyBhbmQgYWxsb3cgdGhlIGNyb3Nzd2FsayB0byBncm93IGEgZmFpciBhbW91bnQgaW4gc2l6ZSB0byBhbGxvdyBOVUxMcyBpbiBhbnkgb2YgdGhlIGlkZW50aWZpZXJzLiBSZXZpc2UgdGhlIGRvY3VtZW50YXRpb24gdG8gcmVmbGVjdCB0aGUgZXhwYW5zaW9uLg0KSCkgQSB1c2VyIGNhbm5vdCBjb25uZWN0IFdRUCBzaXRlcyB0byB0aGUgTkhEUGx1c1YyIHJlcHJlc2VudGF0aW9uIG9mIGxha2VzLiBFeGFtcGxlOiAyIE5IRFBsdXNWMiBsYWtlcyB0byAxIExBR09TLVVTIGxha2UuIFNPTFVUSU9OOiBSZWZpbmUgdGhlIGVudGl0eS1yZWxhdGlvbnNoaXAgbW9kZWwgdG8gam9pbiBiZXR3ZWVuIHRoZSBXUVAgYW5kIE5IRFBsdXNWMiBkaXJlY3RseS4gUmV3b3JrIHN1YnNlcXVlbnQgam9pbnMgaW4gdGhlIHNjcmlwdCB0byBhY2NvbW9kYXRlIHRoZSBjaGFuZ2UuIFRoaXMgY2hhbmdlIHByb2JhYmx5IHdvbid0IGFmZmVjdCB0aGUgb3ZlcmFsbCBzaXplIG9yIHVzYWJpbGl0eSBvZiB0aGUgY3Jvc3N3YWxrIHRvbyBtdWNoLg0KDQojIyBQcm9wb3NlZCBFUiBEaWFncmFtIGRlbW9uc3RyYXRpbmcgY2hhbmdlICJBIiBhbmQgIkgiIGFib3ZlDQohWypQcm9wb3NlZCBlbnRpdHktcmVsYXRpb25zaGlwIGRpYWdyYW0gc2hvd2luZyB0d28gYWRkaXRpb25zLCBpbiBjb2xvcipdKC4vaW1hZ2VzL0VSRF9wcm9wb3NlZC5QTkcpDQoNCiMgTGluayB0byBEZW1vIGRvY3VtZW50DQpZb3UgY2FuIGZpbmQgYSBkZW1vbnN0cmF0aW9uIG9mIExBR09TIExha2UgTGluayBbaGVyZV0oLi9MQUdPU19MYWtlX0xpbmtfRGVtby5uYi5odG1sKQ==