The purpose of this exercise is to help familiarize you with simple ways to explore attributes in various datasets. These skills will help you extract new datasets, connect to tabular data, and qualitatively compare different variables.

1 The Introduction

With the unprecedented growth in middle Tennessee, the Montgomery County Commission, Stormwater Management, and Health Department are working with the Tennessee Department of Environment and Conservation on an initiative to assess the relationship of brownfield sites to our community and watersheds. Brownfields are locations in communities that pose risks to future land use and development as a result of previous land use practices, particularly commercial and industrial (check out more information on brownfields here: https://www.osha.gov/brownfields/brownfields-qna). They often contain high levels of soil and water contamination, and in some cases pollutants can remain in the ecosystem for decades. Unfortunately, brownfields are often point source locations for ground and surface water contamination. The goal of the initiative is to determine if there are any spatial characteristics of these hazardous locations that have the potential to impact current and future residents of the area. The primary objectives of the initative are to: a) examine the location of brownfields in the county, b) determine which watersheds would be primarily impacted, and c) ascertain if there is a relationship between brownfield sites and any particular demographics in the county. With these three objectives, the county partners may make data-informed decisions to best support and prioritize programs that keep our community and environment safe.

In this exercise you will:

  • Continue working with geoprocessing tools
  • Obtain and import data from external sources
  • Learn to link tabular data
  • Qualitatively compare datasets

Software specific directions can be found for each step below. Please submit the answer to the questions and your final map by the due date.

1.1 Step One: The Data

The datasets used in this exercise will be found on the Exercise 5 Github Page, previous exercises such as Exercise 2 and Exercise 3, and also from the Tennessee Geographic Information Council. TN GIS maintains a number of datasets in their collections that are useful for projects involving the state of Tennessee.

View Directions in ArcGIS Pro

As with previous exercises you should begin by launching ArcGIS Pro, creating a new blank template, and creating a folder for this specific exercise. You should now see the typical starting screen that greeted you in all of the previous exercises. While some of the data for this exercise you may already have in previous exercise folders, you will start this lab by downloading a dataset from TN GIS. While they maintain a number of quality collections, you will specifically download the statewide watershed coverage (12 digit Hydrologic Unit Code) for Tennessee. This information can be found at the following link: http://www.tngis.org/water.htm. On that page you will find the link for “Download Watershed Coverage”. Click the link, and using the download button Google Drive Download Button in the upper-right corner, save the tn_wbd zip file to your project folder.

TN GIS Water Data Download

Once you have downloaded the file, navigate to the saved location to unzip the file. Within the unzipped folder you will find three additional folders titled:

  • tn_8dig_huc
  • tn_12dig_huc
  • tn_250k_huc

These are watershed files at varying levels of detail. For hydrologic units you are looking for one with the largest number of digits to get the largest scale data. So for this exercise you will unzip the tn_12dig_huc dataset.

tn_12dig_huc.zip extract

Finally, with that final folder extracted you will find a folder titled hydrologic_units that will contain a shapefile named wbdhu12_a_tn.shp that will be used in this exercise. This is the polygon file representing the 12 digit hydrologic unit codes for the entire state of Tennessee.

Next, you will need the tornado_data file from Exercise 2 and the census_tracts data from Exercise 3. You have a few options for obtaining this data. You can download the data again (but this time to the new project folder), you can navigate to the Exercise 2 and Exercise 3 project folders, respectively, on your computer and copy the zip files to the Exercise 5 project folder, or you can copy the data over using the catalog pane in ArcGIS Pro. While the first two options are relatively straight forward, it is important to learn how to navigate and use the catalog in ArcGIS.

On the View tab, click the Catalog Pane button Catalong Pane Button to open the Catalog Window Pane on the right side of the screen. On the project tab, right-click on the folders option and click "Add Folder Connection. In the resulting window navigate to the folder you would like to connect to and single-click the folder to select it. You don’t want to double-click into the folder. You should see the name of the folder appear at the bottom of the window and the OK button should be available.

Accessing Catalog Pane

Once you have connected to the additional folders you want to use in conjunction with this project you can navigate to them within the Folders link in the Catalog Pane. While you could add data directly from the other folders, the best practice might be to copy the data from one project to another. If for example you plan to alter the data then using it directly from the previous folder would alter it there as well. This could cause future issues when returning to that project. For this exercise you can navigate to the Exercise 2 folder and copy the tornado_data file and paste it in the Exercise 5 folder. This is the safest way to move data such as shapefiles or geodatabases. Because the various data types contain numerous individual files to make up a dataset, catalog will copy/move them all correctly. If you tried to move them using File Explorer and missed one of the files associated with that data it might not work appropriately. So for Exercise 5, you will need to copy the tornado_data and montco_tracts data from exercises two and three respectively.

Copy and Paste Data in Catalog Pane

Finally, you will need to download the Brownfields and Demographics data from the Exercise 5, GitHub Data page. Save both in your Exercise 5 project folder and unzip the brownfields.zip file to access the dataset.

Question No. 1
Using File Explorer, examine the dataset contained in the brownfields.zip file and answer the following question:
What is the common name of the extracted files? How many are there? What are the various file extensions?
The library of Congress has a great description of the various extensions here.

View directions in QGIS

As with previous exercises you should begin by launching QGIS, creating a new empty project, and creating a project folder for this specific exercise. You should now see the typical starting screen that greeted you in all of the previous exercises. While some of the data for this exercise you may already have in previous exercise folders, you will start this lab by downloading a dataset from TN GIS. While they maintain a number of quality collections, you will specifically download the statewide watershed coverage (12 digit Hydrologic Unit Code) for Tennessee. This information can be found at the following link: http://www.tngis.org/water.htm. On that page you will find the link for “Download Watershed Coverage”. Click the link, and using the download button Google Drive Download Button in the upper-right corner, save the tn_wbd zip file to your project folder.

TN GIS Water Data Download

Once you have downloaded the file, navigate to the saved location to unzip the file. Within the unzipped folder you will find three additional folders titled:

  • tn_8dig_huc
  • tn_12dig_huc
  • tn_250k_huc

These are watershed files at varying levels of detail. For hydrologic units you are looking for one with the largest number of digits to get the largest scale data. So for this exercise you will unzip the tn_12dig_huc dataset.

tn_12dig_huc.zip extract

Finally, with that final folder extracted you will find a folder titled hydrologic_units that will contain a shapefile named wbdhu12_a_tn.shp that will be used in this exercise. This is the polygon file representing the 12 digit hydrologic unit codes for the entire state of Tennessee.

Next, you will need the tornado_data file from Exercise 2 and the census_tracts data from Exercise 3. You have a few options for obtaining this data. You can download the data again (but this time to the new project folder), you can navigate to the Exercise 2 and Exercise 3 project folders, respectively, on your computer and copy the zip files to the Exercise 5 project folder, or you can copy the data over using the browser window in QGIS. While the first two options are relatively straight forward, it is important to be confident navigating and using the browser in QGIS.

If you created a “favorites” folder you will most likely navigate within that location, however, if you haven’t created a favorite folder you will search through your drives for the tornado_data file from Exercise 2. Once you locate the file, right/CRTL click on the file and select Export Layer > To File…. In the resulting window select ESRI Shapefile as the “Format”, for the “File name” click on the browse button Browse Location Button and give it a file name and save it to your Exercise 5 project folder. If you check the “Add Saved File to Map” button and click OK the file will be added to your layers.

Export file from Browser

Repeat this process for the census_tracts data from Exercise 3. While you could add data directly from the other folders, the best practice might be to export the data from one project to another. If for example you plan to alter the data then using it directly from the previous folder would alter it there as well. This could cause future issues when returning to that project. With these two files added to your layers you only need to download the Brownfields and Demographics data from the Exercise 5, GitHub Data page. Save both in your Exercise 5 project folder and unzip the brownfields.zip file to access the dataset.

Question No. 1
Using File Explorer/Finder, examine the dataset contained in the brownfields.zip file and answer the following question:
What is the common name of the extracted files? How many are there? What are the various file extensions?

The library of Congress has a great description of the various extensions here.


View directions in R

Before you begin, you will need to open the Ex5 Colab Notebook and insert tocolab after github in the URL to open in the Colab Environment. As you have seen before, R requires various packages to complete certain analyses. In this exercise you will be using a large number of packages including: googledrive, tidyverse, ggsn, cowplot, maps, mapproj, raster, rgeos, rgdal, sp, sf, biscale. Each of these packages also contain various dependencies so it will take a while to load. In previous exercises you installed and loaded packages individually. This requires two lines of code for each package. Therefore this exercise would begin with twenty-four lines to install and load the necessary packages. So in this exercise you will learn to install and load the packages in a three line script. The first line lists the packages, the second line installs all packages, and the third line loads them. In later exercises you will learn to use a library management package to check for libraries on your computer, install them if necessary, and load the packages necessary for the project. For this exercise you will use the following script:

packages<-c('googledrive','tidyverse','ggsn','cowplot','maps','mapproj',
            'raster','rgeos','rgdal','sp','sf','biscale')
sapply(packages, install.packages, character.only = TRUE)
sapply(packages, require, character.only = TRUE)

As with Exercise 3 the tigris package needs to be loaded separately from other packages with the following script:

devtools::install_github('walkerke/tigris')
library('tigris')

The datasets needed for this exercise include: census tracts from Exercise 3, watersheds data from TN GIS, brownfields information and demographics data from this exercise. As with previous exercises all of the data for this lab will be able to be downloaded direct from either a GitHub Page or from a public website. The data from the TN GIS is stored in a Google Drive folder. Most cloud storage platforms have unique data structure that require more detailed download information than a simple *.csv being stored on a webpage. So to download a file from Google Drive you will use the googledrive package that was installed in the list of packages above.

To avoid connecting your own Google credientials you will begin by using the drive_deauth function which suspends authorization credentials. Depending on your use of Google Drive within R you may need to provide your login credentials or an access token. If you navigate to http://www.tngis.org/water.htm you will find the link for “Download Watershed Coverage”.

TN GIS Water Data Download

By clicking the link, a new window will open with a Google Drive download page. On this screen you can locate the file ID within the URL.

Google Drive Download Link

This ID will be used in the drive_downloads function to obtain the file.

drive_deauth()
drive_download(as_id("0B9UIdGiB_LXOeVVQNm91bGpvUUE"), overwrite = TRUE)

On the Google Colaboratory page you will see a folder button Google Colab Files Button on the left that opens a new pane on the left of the screen. The “directory” for this location is /content/ which can be directly accessed within Colab.

Colab Files Tab

The script above downloaded the tn_wbd.zip file that is now located in the contents folder. You can use the unzip function to extract the necessary data.

unzip('tn_wbd.zip')

In the folders pane you can see three additional files were extracted. These are watershed files at varying levels of detail. For hydrologic units the file option with the largest number of digits (e.g. 8-digit Huc vs 12-digit HUC) provides the largest scale data. So for this exercise you will unzip the tn_12dig_huc.zip dataset. In order to help organize the data, you will add a exdir = call to the script to create a new folder for the data within the contents folder. Because this exercise is specific to Colab the scripts below will differ if you are using different IDE for R.

unzip('tn_12dig_huc.zip', exdir = "/content/watersheds")

Now you can open the watersheds folder and view the contents. Due to the file structure of the zip file, the uncompressed data now contains the characters hydrologic_units\ in front of the file name. R will not permit these characters within a file or object therefore you need to rename the data before you can continue.

Inaccessible File Names

To start this process you will create a list of files in the watershed folder that contains the “hydrologic_units” prefix. Since we need to consistently remove the first seventeen characters, you can use the sub function to remove those characters. Alternatively if you just needed to rename some files you could add characters between the apostrophes.

names <- list.files(path = "/content/watersheds", pattern = "hydrologic_units")
new_names <- sub('.................','',names)

Because file.rename operates at the root directory level, you need to temporarily direct the working directory to the location of the inappropriately named files, rename them, then return to the correct working directory. It is possible there is a way around this, unfortunately via Colab or RStudio I do not know how to use file.name outside of the directory containing the values.

setwd("/content/watersheds")
file.rename(names,new_names)
setwd("/content")

If you navigate back to the files pane you can now see the watershed files have been renamed. To return to the content folder you can use the up directory button Google Colab Up Directory Button.

Renamed File

Now you can use the readOGR function from rgeos to rad in the shapefile to a new object.

watersheds_data <- readOGR("/content/watersheds/wbdhu12_a_tn.shp")

With the watersheds dataset created you need to address the remaining datasets. Using similar steps to previous exercises you will now download and create a brownfields dataset. You will also create a new folder for this data just like in the watershed script above.

download.file('https://github.com/chrismgentry/GIS1-Exercise-5/raw/main/Data/brownfields.zip', 'brownfields.zip')
unzip('brownfields.zip', exdir = "/content/brownfields")
brownfields_data <- readOGR("/content/brownfields/brownfields.shp")

The next dataset to import will be the demographics dataset from the exercise GitHub page. Because the data is a simple *.csv file it can easily be read in with the read.csv function.

demographics <- read.csv('https://raw.githubusercontent.com/chrismgentry/GIS1-Exercise-5/main/Data/demographics.csv')

The final dataset to import is the census tract for Montgomery County. Using the tigris package like in Exercise 3, Step 1 you can use tracts to obtain the dataset.

montco_tracts <- tracts("TN", county = "Montgomery")

Three of these datasets (brownfields, watersheds, and census tracts) are already in spatial data formats. In order to perform further analysis you need to make sure they have the same coordinate reference system (crs).

crs(watersheds_data)
crs(brownfields_data)
crs(montco_tracts)

You can see they are all in different projections. Therefore you need to reproject them under a single crs. For this exercise you will use EPSG:4326 which in R appears as +proj=longlat +datum=WGS84 +no_defs when referenced in the script. Because the brownfields data is already in this crs you can use it or the EPSG to correct the other datasets. Remember from Exercise 3 that data from tigris is in a slightly different spatial data structure ( sf vs. SpatialPolygonsDataFrame) so the process to reproject that data will vary from the watersheds dataset.

watersheds_data <- spTransform(watersheds_data, crs(brownfields_data))
montco_tracts <- st_transform(montco_tracts, 4326)

You can now check the crs information for each dataset and they should all be in EPSG:4326 (or +proj=longlat +datum=WGS84 +no_defs). With the data created and reprojected to the same crs you can move on to the analysis.

Question No. 1
Using the files button on the left, examine the dataset contained in the brownfields.zip file and answer the following question:
What is the common name of the extracted files? How many are there? What are the various file extensions?

The library of Congress has a great description of the various extensions here.

1.2 Step Two: The Analyses

The data collected in the previous section requires additional processing so you can reduce the dataset to only the pertinent information for the analyses. In this step you will use additional geoprocessing techniques and data management tools to link two datasets for further examination.

View Directions in ArcGIS Pro

With the data collected you can now add the brownfields, census tracts, tornado_data, and wbdhu12_a_tn (watersheds) data to your project. Although there are a number of ways of isolating data to make derived datasets (e.g. Select > Lasso in Exercise 4, Step 1), in this exercise you will use another tool from the Geoprocessing Toolbox to complete this task. On the View Tab click on the Geoprocessing Toolbox button Geoprocessing Button to open the Geoprocessing pane on the right side of the screen. By navigating through the tools menus you will find Select under Analysis Tools > Extract. With this tool you will write a simple expression to “select” a small portion of the data you need for further analysis. To do this, double-click the Select tool and in the resulting pane input the following parameters:

  • Input Features = tornado_data*
  • Output Feature Class = Here you will insert the file name you want to use. Click on the folder icon to the right of the field and in the new window save the file as montgomery_county.shp in your project folder.
  • Expression = Click the drop-down button for the new expression Expression Button button and use the drop-down boxes to provide the following information:
    • Where NAME   is equal to   Montgomery
    • Click Run

Select Geoprocessing Tool

*The tornado dataset is only being used to obtain a polygon for Montgomery County for the clip process in the next step.

This will add the new montgomery_county shapefile to your contents. You can now remove the tornado dataset because it will no longer be needed. With the polygon of Montgomery County available you can now use the Clip tool like in Exercise 4, Step One to clip the brownfields and watersheds datasets to reduce them to only those within Montgomery County. If you receive a “Datum conflict” warning, for the purposes of this exercise, you can ignore it an continue with the clip. Recall that the Input Features is the data you want to reduce, the Clip Feature is the data you want it to take the shape of, and Output Feature Class is what you are naming the new file. Refer back to Exercise 4, Step One for more information about Clip.

Select Clipped Datasets

With the new clipped datasets you can remove or just uncheck (in case you want to use them in your final map) the full brownfields and watersheds datasets to reduce clutter. You can also now zoom in closer to view only Montgomery County.

In the final step to prepare the data, you are going to connect a non-spatial data to the census tract dataset. In Step One you downloaded a file titled demographics.csv. This file contains comma-separated values detailing additional demographic data that you need to append to the census tract data. Although the process is relatively straight-forward, there are a number of steps that need to be taken in order to join the data.

First, if you haven’t already, add the demographics.csv file to your table of contents. This can be done from the Catalog Pane or with the “Add Data” button Add Data Button like in previous exercises. Because ArcGIS Pro treats *.csv files as “read only” you need to convert it to a table that can be edited in the software. Now, right-click on the demographics.csv standalone table and go to Data > Export Table. In the resulting window choose the following options:

  • Input Rows = demographics.csv
  • Output Location = Similar to before, navigate only to your project folder and click once to select. In the step you are simply designating the folder the file is to be saved.
  • Output Name = Give the file a new name such as demo_table.dbf

Before clicking OK, you need to expand the Fields section of the window and click on Tract in the Output Fields column. Then click on the Properties Tab and change the Type field to Text. Then click OK. If you continued without changing the field type, the variable would most likely be treated as a numerical value. If you open the attribute table for any dataset and mouse-over the variable column without clicking a pop-up window will appear detailing the Type and other parameters of the variable. In the census dataset from the previous exercise, the NAME variable is Type: Text (7). The seven in parenthesis means the max number of available characters is seven. So before you export a table it is good practice to make sure the variables match the variables you intend to join or that the variables will be treated in a manner necessary for additional analyses.

Export CSV to DBF

The new standalone table should have been added to the Table of Contents. If not you should add it now; the csv table can be removed. Now you can connect the new table to the census tract dataset. Begin by right-clicking on the census data and selecting Joins and Relates > Add Join. In the new Add Join window select the following options (your file names may vary):

  • Input Table = montco_tracts, or whatever you named the census tract information
  • Input Join Field = NAME
  • Join Table = demo_table, or whatever you named the new demographics data
  • Join Table Field = Tract

For this exercise keep the “Keep All Target Features” button checked and if you receive an warning about an indexing error with the census data you can ignore it for this exercise. Then click the Validate Join button. This will pop-up an new window that will describe the process of checking the two datasets to see if they can be joined. At the bottom of the dialog you should see a line that says there were 39 joins. Close that message and click OK to run the join.

Join Datasets

Finally, open the attribute table for the census tracts and scroll to the far right of the table. If the join worked properly you should see a number of additional fields added to the table.

Join Datasets, Attribute Table

This will provide all of the data and information you need to visualize the data and make comparisons of the watersheds.

Question No. 2
How many watersheds cover Montgomery County? Although they have been clipped from their original geometry, which watershed is the largest? Which is the smallest?

View Directions in QGIS

With the data collected you can now add the brownfields, census tracts, tornado_data, and wbdhu12_a_tn (watersheds) data to your project. Although there are a number of ways of isolating data to make derived datasets (e.g. Select Features > Select Features by Freehand in Exercise 4, Step 1), in this exercise you will use another tool from Vector Selection in the Processing Toolbox to complete this task.

Vector Selection

With this tool you will select only a small portion of the data you need for further analysis. To do this, double-click the “Select”Extract by Attribute" tool and in the resulting window input the following parameters (file names may vary):

  • Input layer = tornado_data
  • Selection attribute = NAME
  • Operator = = (equals sign)
  • Value = Montgomery

Remember that in QGIS you have the ability to either create permanent files or temporary layers. Because you will only be using the Montgomery County dataset to clip files later on, you can decide whether to use the browse button Browse Location Button to save the file for future use or just create a temporary file.

Select by Attribute

This will add the new montgomery_county temporary file (or shapefile if saved) to your layers. You can now remove the tornado dataset because it will no longer be needed. You may also consider renaming it if necessary. With the polygon of Montgomery County available you can now use the Clip tool like in Exercise 4, Step One to clip the brownfields and watersheds datasets to reduce them to only those within Montgomery County. Recall that the Input layer is the data you want to reduce (e.g. brownfields or watersheds), the Overlay layer is the data you want it to take the shape of. Refer back to Exercise 4, Step One for more information about Clip. You should go ahead and use the browse button Browse Location Button to save these as permanent files. Be sure to use a naming convention that will allow you to recal what the files are later on (e.g. montco_brownfields).

With the new clipped datasets you can remove or just uncheck (in case you want to use them in your final map) the full brownfields and watersheds datasets to reduce clutter. You can also now zoom in closer to view only Montgomery County.

Montgomery County Datasets

In the final step to prepare the data, you are going to connect a non-spatial data to the census tract dataset. In Step One you downloaded a file titled demographics.csv. This file contains comma-separated values detailing additional demographic data that you need to append to the census tract data. Although the process is relatively straight-forward, there are a number of steps that need to be taken in order to join the data.

First, you will add the demographics.csv using Layer > Add Layer > Add Delimited Text Layer from the menu bar, by clicking the “Add Delimited Layer” button Add Delimited Layer, or by using the shortcut keys CRTL+Shift+T/CMD+Shift+T.

In the resulting window, use the browse button to find the demographics.csv data in your project folder. Be sure that “No geometry (attribute only table)” is selected and the the rest of the information as the default. Click Add.

Text Delimited Dialog

The demographics table should now be added to your layers. To connect it to the population information, right/CRTL click on the census tract data and select “properties”. In the Properties Menu, select the Joins Joins Tab tab from the left side menu. At the bottom of the screen click the plus (+) symbol to add a join. In the new window select the following parameters:

  • Join layer = demographics
  • Join Field = Tract
  • Target field = NAME

Leave the “Cache join layer in memory” checked and scroll down to “Joined Fields”. Click all of the fields and scroll down to the “Custom field name prefix” option and check the box. Remove all of the text in the box and then click OK.

Vector Join Window

Be sure to click OK on the properties window as well to complete the join. Finally, open the attribute table for the census tracts and scroll to the far right of the table. If the join worked properly you should see a number of additional fields added to the table.

Join Table

This will provide all of the data and information you need to visualize the data and make comparisons of the watersheds.

Question No. 2
How many watersheds cover Montgomery County? Although they have been clipped from their original geometry, which watershed is the largest? Which is the smallest?

View Directions in R

There are some additional processing steps needed on the collected datasets before you can move on to the visualizations. In Exercise 3, Step 2 you used the merge function to combined the census tracts and population data. In this exercise you will repeat those steps to connect the demographics dataset to the census tracts.

census_tracts <- merge(x = montco_tracts, y = demographics, by.x = "NAME", by.y = "Tract", all = TRUE)

By plotting the brownfield or watersheds data using ggplot2 or quickly using plot(x) where x = the name of the dataset, you will like be able to determine that the data included extends far beyond the boundaries of Montgomery County. In the previous exercise the intersect function was used to clip out the counties within the hurricane buffer. In this exercise you will use the crop function to see how it varies from intersect. For this step you will want to crop the brownfields and watersheds datasets by the census tracts to retain only those within the county.

montco_brownfields <- crop(brownfields_data,census_tracts)
montco_watersheds <- crop(watersheds_data,census_tracts)

If you create a ggplot() of the data you will see how the datasets were subset. Essentially, a bounding box (extent of the dataset from the most upper-left portion to the lower-right) was created for the census tract data and any data within that box was retained. Why might this potentially be problematic in some instances? In what instance might this be the best method?

Before proceeding to the visualization portion you need to create a couple tables to help answer the questions asked by your community partners. One being how many brownfield occur within each watershed and census tract. To do this you can use the over function from the rgeos to create a count of the overlapping data. This is called a spatial join and it returns a count of the points that fall within a specific polygon. More information on over can be found here.

brownfields_per_watershed <- over(montco_brownfields,montco_watersheds)
watershed_table <- as.data.frame(table(brownfields_per_watershed$HUC_12))
watershed_table <- transform(watershed_table, Var1 = as.character(Var1))
colnames(watershed_table) <- c("HUC_12","BF_Count")
watershed_table

In the script above, over created the spatial join analysis. The next line converted the information into a dataframe table with columns of variables and rows of observations. However, because the watershed names (HUC_12) a numeric, the table would not be able to be joined to a previous dataset because the numeric name for the watershed was treated as a character (nominal data). So the transform function was used to convert the names to characters. Finally, colnames was used to rename the columns to names that are more appropriate for the data.

Once the table has been created you will need to connect the table to the original data so the information can potentially be included in the visualization. Because some of the watershed do no contain a brownfield there will be NA values reported for those observations. So there will be a line added to replace the NA values with zeros in the script below:

montco_watershed_data <- merge(x = montco_watersheds, y = watershed_table, by.x = "HUC_12", by.y = "HUC_12", all = TRUE)
montco_watershed_data@data$BF_Count[is.na(montco_watershed_data@data$BF_Count)] <- 0
montco_watershed_data@data

While you have seen the merge function before, notice the syntax for the second line. Because the data is a SpatialPolygonsDataFrame the data table that contains the data will be held in a slot (a container for information in certain file types) call data. So to examine the information you will call to the object and add _@data_ following the object name. In the example above, the script is identifying the BF_Count variable in the watersheds data slot and saying “if there is a na value in that variable within the slot, it should be replaced with a 0.” If you examine the object only you will notice there are actually several slots including:

  • bb = bounding box
  • data = the data table
  • plotOrder = the order of the polygons when drawn
  • polygons = the longitude and latitude values corresponding to the different polygons
  • proj4string = the crs information

Remember that you should always examine new datasets when they are imported into your project. Because the census tract data is a slightly different format than the watershed you will complete a very similar process to the above script with a slight modification to convert the census tracts to a SpatialPolygonsDataFrame.

census_tracts_spdf <- sf::as_Spatial(census_tracts)
brownfields_per_tract <- over(montco_brownfields,census_tracts_spdf)
census_tract_table <- as.data.frame(table(brownfields_per_tract$NAME))
census_tract_table <- transform(census_tract_table, Var1 = as.character(Var1), Freq = as.numeric(Freq))
colnames(census_tract_table) <- c("Name","BF_Count")
census_tract_table

With the table created you can now attach it to the original census data.

census_tract_dataset <- merge(x = census_tracts, y = census_tract_table, by.x = "NAME", by.y = "Name", all = TRUE)
census_tract_dataset$BF_Count[is.na(census_tract_dataset$BF_Count)] <- 0
str(census_tract_dataset)

while you could have kept the SpatialPolygonsDataFrame version of the census data, it is important to know how to manage different classes of data. So in this exercise the census tract data will continue to be simple features (sf) data while the watershed data will be sp.

If you examine the brownfields dataset it is also a type of sp data called a SpatialPointsDataFrame. Because the values are points and not polygons you can see the type changes accordingly. If you create a visualization of the data you will find that while crop worked to subset the information based on the bounding rectangle of the census tracts, because of the shape of Montgomery County and the location of the brownfields one record was retained erroneously. The first record “The Compost Company” is located south of the county and therefore needs to be removed from the dataset. To do this you will convert the brownfields dataset to a data frame and remove the first row of data. Because items in a data frame can be identified by row (first value) and column (second value) simply adding [-1,] behind the object name will “subrtract” the entire row from the dataset. Since you are already editing the data, it would also make sense to rename the column to names that match ggplot2 nomenclature.

brownfields_dataset <- as.data.frame(montco_brownfields)
colnames(brownfields_dataset) <- c("Name", "long", "lat", "NA")
brownfields_dataset <- brownfields_dataset[-1,]
brownfields_dataset

Finally, just in case you need a simple outline of Montgomery County for your visualization in the next step you can create an object polygon of the county with a similar script to create the states information in Exercise 2, Step 1.

counties <- map_data("county")
tn_counties <- subset(counties, region == "tennessee")
montco <- subset(tn_counties, subregion == "montgomery")
Question No. 2
How many watersheds cover Montgomery County? Although they have been clipped from their original geometry, which watershed is the largest? Which is the smallest?
HINT: View acres in the watershed dataset.

1.3 Step Three: The Visualization

In this step you will need to examine the spatial distribution of brownfields within the watersheds of Montgomery County and make some qualitative interpretations of potentially impacted urban areas.

View directions in ArcGIS Pro

Examine the spatial distribution of the brownfield throughout the county. The clustering should be relatively apparent and might match up with your knowledge of industrial activities in the various areas of Montgomery County. In order to help quantify the number of brownfields in each watershed you can use a Spatial join to create a count variable for this information. To do this, right-click on the montgomery county watershed dataset and go to Join and Relates > Spatial Join

Spatial Join Datasets

In the resulting window, select the following parameters (your file names may vary):

  • Target Features = Montgomery County watersheds
  • Join Features = Montgomery County brownfields
  • Output Feature Class = This is where you name the new dataset. For continuity you can name it something like: brownfields_per_watershed.shp
  • Join Operation = Choose “Join one to one” from the drop-down menu
    • Keep all Target Features should remain checked
  • Match Option = Choose “Intersect” from the drop-down menu

You can leave the remaining items blank and click OK.

Spatial Join Datasets Dialog

By examining the attribute table for the new dataset you should see a new variable called Join_Count. This is the number of brownfields that occur within each watershed.

Using the skills you learned in Exercises Two, Three, and Four you can now make a map that shows Montgomery County, the location of brownfields and watersheds in a graduated color scheme by number of brownfields. Remember to include cartographic elements such as legend, scale bar, north arrow, etc. In this visualization you may also want to add a different basemap or inset map that provides additional supporting information.

Question No. 3
Which watershed contains the most brownfields?

View directions in QGIS

Examine the spatial distribution of the brownfield throughout the county. The clustering should be relatively apparent and might match up with your knowledge of industrial activities in the various areas of Montgomery County. In order to help quantify the number of brownfields in each watershed you can use Join attributes by location (Summary) from the Vector General menu in the Processing Toolbox. this will create a count of the total number of brownfields per watershed polygon. In the Join attributes by location (Summary) select the following options (layer names may vary):

  • Input layer = watershed layer for Montgomery County
  • Join layer = brownfields layer for Montgomer County
  • Geometric predicate = Intersects

In the Summaries to calculate… you will click the browse button and select only “count”. When selected, click the blue arrow button blue Arrow to return to the previous page. As before, you can leave this as a temporary file* or you can choose to create a permanent file for future use. Now click Run.

Spatial Join Datasets Dialog

*If you choose to make a temporary file you should rename it in the layers with a sensible name.

By examining the attribute table for the new dataset you should see a new variable called Name_count. This is the number of brownfields that occur within each watershed. Unfortunately, some of the cells are populated with “Null” values. You need to remove these in order to create a proper graduated color scheme. To do this you will open the attribute table for newly created dataset and click the Field calculator button Field Calculator button. In the new window uncheck the box for “Create a new field” and check the box for “Update existing field”. In the drop-down menu below the box select Name_count. In the Expression box type the following and click OK:

if("Name_count" is null, 0, "Name_count")

Field Calculator

This will replace all of the null values with zero values. Finally, click the Toggle editing mode button toggle Editing and save the changes to the table.

Now, using the skills you learned in Exercises Two, Three, and Four you can now make a map that shows Montgomery County, the location of brownfields and watersheds in a graduated color scheme by number of brownfields. Remember to include cartographic elements such as legend, scale bar, north arrow, etc. In this visualization you may also want to add a different basemap or inset map that provides additional supporting information.

Question No. 3
Which watershed contains the most brownfields?

View directions in R

Examine the spatial distribution of the brownfield throughout the county. The clustering should be relatively apparent and might match up with your knowledge of industrial activities in the various areas of Montgomery County. Use the skills you developed in Exercises 4, 3, and 2 to complete the scripts below and create the visualizations for the number of brownfields per watershed and the number of brownfields per census tract. Don’t forget to add all of the necessary map elements and feel free to add any ancillary data from this or previous exercises that enhance your map.

Watershed Map:

#ggplot() +
#geom_polygon(data = DATASET, aes(x=long, y=lat, group=group, fill = SELECT THE APPROPRIATE VARIABLE), color = "gray", size = 0.25, linetype="dashed") + 
#geom_polygon(data = montco, aes(x=long, y=lat, group=group), fill = NA, color = "black", size = 1) + 
#geom_point(data = DATASET, aes(x=long, y=lat), color = "SELECT A COLOR") +
#coord_fixed() +
#ADD THE NECESSARY ELEMENTS HERE

Census Tract Map:

#ggplot() +
#geom_sf(data = DATASET, aes(fill = SELECT THE APPROPRIATE VARIABLE)) + scale_fill_viridis_c(direction = -1, option = "A") +
#geom_point(data = DATASET, aes(x=long, y=lat), color = "red") +
#coord_sf() +
#ADD THE NECESSARY ELEMENTS HERE

Remember to remove all # comment tags before running the edited scripts.

Question No. 3
Which watershed contains the most brownfields?

1.4 Step Four: The County Commisson Report

After discussing the results of the previous analysis with your colleagues at County Commission, Stormwater Management, Health Department, and TDEC, they are interested in seeing how the location of brownfields impacts the community. Although the commission districts do not perfectly replicate the census tracts, the County Commissioners and the Health Department want to know if the brownfield sites are directly related to census tracts with large minority populations. They are concerned by a recently published report that states:

“While there is no single way to characterize communities located near our sites, this population is more minority, low income, linguistically isolated, and less likely to have a high school education than the U.S. population as a whole. As a result, these communities may have fewer resources with which to address concerns about their health and environment.”

During these discussions the Health Department would also like to know if the areas with a high number of brownfields have higher populations of children.

View directions in ArcGIS Pro

Using the skills you learned in this and previous exercises, create a new spatial join between the census tracts and brownfields datasets (for this exercise ignore any datum warning). As with the previous spatial join, you should now have an additional variable labeled “Join_Count” that details the number of brownfields per census tract.

One way you can view two variables at once on a map is to create bivariate symbology.

Bivariate Color Selection

This creates a grid of colors with an X and Y axis with the following categories:

Bivariate Color Scheme

  • Where the Bottom Left cell indicates low values in both variables
  • Where the Upper Left cell indicates high values in the first variable and low values in the second variable
  • Where the Bottom Right cell indicates low values in the first variable and high values in the second variable
  • Where the Upper Right cell indicates high values in the first variable and high values in the second variable

The other grid cells represent midpoints in the variables. The variables can be selected in the symbology pane where “Field 1” is one variable and “Field 2” is the other variable. So to visualize brownfields and one of the population demographics select one for each field. For “Grid Size” select 3x3. You can select your own color scheme with the drop-down menu. In the fields section below, you can rename the fields (e.g. “join count” means nothing so give it an appropriate name).

Bivariate Color Options

With these settings you should have a symbology that shows if a census tract is high or low in either of the particular variables. Test a number of different variable combinations with the count of brownfields and various demographic categories.

Question No. 4
Which census tract contains the most brownfields?

View directions in QGIS

Using the skills you learned in this and previous exercises, create a new Join attributes by location (Summary) between the census_tracts and brownfields datasets (for this exercise ignore any datum warning). As with the previous spatial join, you should now have an additional variable labeled “Name_count” that details the number of brownfields per census tract.

One way you can view two variables at once on a map is to create bivariate symbology. This creates a grid of colors with an X and Y axis with the following categories:

Bivariate Color Scheme

  • Where the Bottom Left cell indicates low values in both variables
  • Where the Upper Left cell indicates high values in the first variable and low values in the second variable
  • Where the Bottom Right cell indicates low values in the first variable and high values in the second variable
  • Where the Upper Right cell indicates high values in the first variable and high values in the second variable

The other grid cells represent midpoints in the variables. You can create these bivariate maps in QGIS with some editing of the individual color palettes in your graduate colors map and by using a plug-in to create the legend. In order to create the map you first need to duplicate your layer. This example will use the census tract dataset with the “Name_count” variable for number of brownfields and variables for different demographics such as total population (tot_pop). To duplicate a layer, right/CRTL click on a layer and select Duplicate Layer. If it helps you to keep the two layers organized, you can amend their layer name to include the variable used for the graduated colors (e.g. tracts_brownfields_count or tracts_brownfields_pop). Otherwise just remember what each one is displaying.

Next, you will need to create a graduated symbology for each layer with three (3) categories and a specific color palette. Because bivariate maps blend two color schemes it is important to have the appropriate color selection. Here is an example of several bivariate color palettes from Joshua Stevens

Bivariate Color Palettes

This example will use the second color palette. There are a few steps required to match your graduated colors categories to the color palettes on the X and Y axes in the image above:

  1. Select the appropriate value. Tot_Pop and Name_Count will be used for this example.
  2. Set the classes to 3.
  3. Double-click on the first of the selected colors.
  4. In the new Symbol Selector window, click on the color bar.
  5. In the next Select Color window, type in the HTML notation that matches your selected palette. Remember, one of your layers will start at the bottom left and work up and the other will start and the bottom left and work to the right.

Finally, click OK on the windows in Steps 3 and 4 and repeat the process for the next color moving progressively up or right on the selected bivariate palette depending on the layer. This process will need to be completed for both of the layers (one with the brownfield count and the other with a demographic variable) you will use in your bivariate map.

Bivariate Color Palette Steps

Once you have completed this process for each of the layers you should return to the properties menu of the first layer and under the Symbology tab scroll down to Layer Rendering and expand the options to see the options for Blending mode. Choose multiply for the layer, and normal for the feature and click OK.

Layer Rendering

With both layers viewable you should now have a bivariate color palette for the data.

Bivariate Map

Because QGIS is unable to interpret the appropriate legend style from the available data you need to add a plug-in. Click Plugins > Manage and Install Plugins from the menu bar.

Install and Manage Plugins

Next, search for “Bivariate Legend” in the search bar. Be sure All is selected in the left side column. This should bring up the Bivariate Legend plugin. Click Install Plugin in the lower right of the window to install the legend generator.

Install Bivariate Legend Plugin

With the plugin installed you can return to your project. You will now have a Bivariate Legend button Bivariate Legend button on your toolbar. Click the button to open the legend generator. Select the appropriate Top layer from the drop-down menu and click the box for Reverse colors. Select the appropriate Bottom layer, set the Square width to 48, and choose Multiply for the drop-down menu below. Then click Generate legend.

Bivariate Legend Generator

Finally, click Export legend to image and save it in your project folder with a .png extension. In your layout, use the Add image button Add image to layout button and draw the image box while holding the shift key to constrain the box to a perfect square. Next, right-click in the box and go to Item properties to locate the image file. In the properties pane, select Raster Image and navigate to your project folder to add the image.

Insert Legend Image

Remember that this is now simply an image which means you will need to manually create the legend using the image and inserted text. Be sure you remember which data belongs on which axis and think about how you want the reader to interpret the information. Here is an example of one that could be used for the legend created above.

Bivariate Legend Example

You should experiment with different demographics to see how they relate to the number of brownfields before completing the assignment. You will want to select the variable that you believe shows which demographic would most be impacted by the presence of brownfields in the various tracts.

Question No. 4
Which census tract contains the most brownfields?

View directions in R

As stated above, the County Commissioners and the Health Department want to see the relationship between census tracts with large minority populations and brownfields and the Health Department would also like to see the relationship between brownfields juvenile populations. The visualizations you created above simply show the number of brownfields per watershed/census tract. You could create a qualitative visualization where demographics (either minority class or age class) is used as the fill with brownfield locations as an overlay. However, you can also create a two variable quantitative map called a bivariate map that displays quantitative categories for two different variables. This creates a grid of colors with an X and Y axis with the following categories:

Bivariate Color Scheme

  • Where the Bottom Left cell indicates low values in both variables
  • Where the Upper Left cell indicates high values in the first variable and low values in the second variable
  • Where the Bottom Right cell indicates low values in the first variable and high values in the second variable
  • Where the Upper Right cell indicates high values in the first variable and high values in the second variable

The other grid cells represent midpoints in the variables. You can create these bivariate maps in R manually or by using the biscale package loaded at the beginning of this exercise. Because bivariate maps blend two color schemes it is important to have the appropriate color selection. Graduated symbology palettes have been created that cover a range of color possibilities for the legend. These include:

Biscale Bivariate Color Palettes

Like the visualization you created for Exercise 3, Step 3, you will rely on syntax from cowplot to overlay the map and legend from biscale. However, currently the only demographic data in this exercise is by race. So before you begin this process you need to take the additional step of connecting the population data from Exercise 3, Step 2. The same script can be used to obtain the dataset:

population <- read.csv('https://raw.githubusercontent.com/chrismgentry/GIS1-Exercise-3/main/Data/mont_co_pop.csv', colClasses=c(Tract="character"))

To connect the data to the census tract dataset complete the following script:

#census_with_pop <- merge(x = census_tract_dataset, y = DATASET, by.x = "VARIABLE", by.y = "VARIABLE", all = TRUE)

If you have questions about completing the script above review the information from Exercise 3, Step 2 or from similar steps earlier in this exercise.

To create the bivariate dataset you need to use the bi_class function from biscale.

bivariate_data <- bi_class(census_with_pop, x = total_pop, y = BF_Count, dim = 3, style = "jenks")

In this script you identify the dataset to be used to create the bi_class data. You identify the x variable, in this example total population and the y variable for the count of brownfields. Finally you provide the number of dimensions (3) and style to calculate the divisions in the data. For this example you will use Jenks Natural Breaks Classification simply identified as “jenks”.

Now you can use the information above to create the visualization based on total population. You will need to create a new code block or alter the one above to identify an x variable appropriate to answer the questions posed by the County Commission and Health Department.

bivariate_map <- ggplot() +
  geom_sf(data = bivariate_data, mapping = aes(fill = bi_class), color = "white", size = 0.1, show.legend = FALSE) +
  geom_point(data = brownfields_dataset, aes(x=long, y=lat), color = "red") + 
  bi_scale_fill(pal = "DkViolet", dim = 3) +
  theme_void()

You can use this same example script to create a map based on a different demographic variable (x) as long as it is identified appropriately in the bivariate_data script block above. Next you need to create an object to serve as the legend. Unfortunately, because biscale legends are not linked to the data you will need to overlay it as an “image”. So be careful that any changes made to the data are reflected in the legend as well.

legend <- bi_legend(pal = "DkViolet",
                    dim = 3,
                    xlab = "Total Population",
                    ylab = "No. Brownfields",
                    size = 10)

With the map and legend objects created you can now script the base of the final map using the same process as the last exercise.

final_map <- ggdraw() +
  draw_plot(bivariate_map, 0, 0, 1, 1) +
  draw_plot(legend, 0.7, 0, 0.25, 0.25)
final_map

For this map, total population was simply used to provide an example script. So to finish this exercise you will need to alter the x variable in the bivariate_data script to determine if there is any relationship between demographics (race or age) for the County Commission and Health Department.

Question No. 4
Which census tract contains the most brownfields?

2 The Write-Up

In the report you provide to the County Commission, Stormwater Management, Health Department, and TDEC please provide the following information:

  • Which watershed is most potentially impacted by brownfields?
  • What is the total population of the tracts with brownfields?
  • What demographic could be the most impacted by brownfields?
    • By examining the tract with the most brownfields, what demographic is the most impacted, and how does it relate to location within the city/county?

Be sure to include mpas you created to support your report. When complete, send a link to your Colab Notebook or word document with answers to Questions 1-4 and your completed map(s) via email.

LS0tDQp0aXRsZTogIkV4ZXJjaXNlIDU6IFNpbXBsZSBEYXRhIEV4cGxvcmF0aW9uIDxicj48c21hbGw+R2VvZ3JhcGhpYyBJbmZvcm1hdGlvbiBTeXN0ZW1zIDEgTGFiPC9zbWFsbD48L2JyPiINCmF1dGhvcjogIkdFT0cgMzE1MCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICByb3dzLnByaW50OiAxMA0KICAgIHRoZW1lOiBjb3Ntbw0KICAgIGhpZ2hsaWdodDogYnJlZXplZGFyaw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogICAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCmVkaXRvcl9vcHRpb25zOg0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQogIG1vZGU6IGdmbQ0KLS0tDQoNCmBgYHs9aHRtbH0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCmgxLnRpdGxlIHsNCiAgZm9udC1zaXplOiA0MHB4Ow0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KLnpvb20gew0KICB0cmFuc2Zvcm0tb3JpZ2luOiA0MCUgNTAlIDA7DQogIHRyYW5zaXRpb246IHRyYW5zZm9ybSAuMnM7DQogIG1hcmdpbjogMCBhdXRvOw0KfQ0KLnpvb20gaW1new0KCXdpZHRoOmF1dG87DQoJaGVpZ2h0OmF1dG87CQ0KfQ0KLnpvb206aG92ZXIgew0KICB0cmFuc2Zvcm06IHNjYWxlKDIpOw0KfQ0KDQp0aCwgdGQge3BhZGRpbmc6IDVweDt9DQoNCjwvc3R5bGU+DQpgYGANCjxocj48L2hyPg0KDQpUaGUgcHVycG9zZSBvZiB0aGlzIGV4ZXJjaXNlIGlzIHRvIGhlbHAgZmFtaWxpYXJpemUgeW91IHdpdGggc2ltcGxlIHdheXMgdG8gZXhwbG9yZSBhdHRyaWJ1dGVzIGluIHZhcmlvdXMgZGF0YXNldHMuIFRoZXNlIHNraWxscyB3aWxsIGhlbHAgeW91IGV4dHJhY3QgbmV3IGRhdGFzZXRzLCBjb25uZWN0IHRvIHRhYnVsYXIgZGF0YSwgYW5kIHF1YWxpdGF0aXZlbHkgY29tcGFyZSBkaWZmZXJlbnQgdmFyaWFibGVzLg0KDQojIFRoZSBJbnRyb2R1Y3Rpb24NCg0KV2l0aCB0aGUgdW5wcmVjZWRlbnRlZCBncm93dGggaW4gbWlkZGxlIFRlbm5lc3NlZSwgdGhlIE1vbnRnb21lcnkgQ291bnR5IENvbW1pc3Npb24sIFN0b3Jtd2F0ZXIgTWFuYWdlbWVudCwgYW5kIEhlYWx0aCBEZXBhcnRtZW50IGFyZSB3b3JraW5nIHdpdGggdGhlIFRlbm5lc3NlZSBEZXBhcnRtZW50IG9mIEVudmlyb25tZW50IGFuZCBDb25zZXJ2YXRpb24gb24gYW4gaW5pdGlhdGl2ZSB0byBhc3Nlc3MgdGhlIHJlbGF0aW9uc2hpcCBvZiBicm93bmZpZWxkIHNpdGVzIHRvIG91ciBjb21tdW5pdHkgYW5kIHdhdGVyc2hlZHMuIEJyb3duZmllbGRzIGFyZSBsb2NhdGlvbnMgaW4gY29tbXVuaXRpZXMgdGhhdCBwb3NlIHJpc2tzIHRvIGZ1dHVyZSBsYW5kIHVzZSBhbmQgZGV2ZWxvcG1lbnQgYXMgYSByZXN1bHQgb2YgcHJldmlvdXMgbGFuZCB1c2UgcHJhY3RpY2VzLCBwYXJ0aWN1bGFybHkgY29tbWVyY2lhbCBhbmQgaW5kdXN0cmlhbCAoY2hlY2sgb3V0IG1vcmUgaW5mb3JtYXRpb24gb24gYnJvd25maWVsZHMgaGVyZTogW2h0dHBzOi8vd3d3Lm9zaGEuZ292L2Jyb3duZmllbGRzL2Jyb3duZmllbGRzLXFuYV0oaHR0cHM6Ly93d3cub3NoYS5nb3YvYnJvd25maWVsZHMvYnJvd25maWVsZHMtcW5hKSkuIFRoZXkgb2Z0ZW4gY29udGFpbiBoaWdoIGxldmVscyBvZiBzb2lsIGFuZCB3YXRlciBjb250YW1pbmF0aW9uLCBhbmQgaW4gc29tZSBjYXNlcyBwb2xsdXRhbnRzIGNhbiByZW1haW4gaW4gdGhlIGVjb3N5c3RlbSBmb3IgZGVjYWRlcy4gVW5mb3J0dW5hdGVseSwgYnJvd25maWVsZHMgYXJlIG9mdGVuIHBvaW50IHNvdXJjZSBsb2NhdGlvbnMgZm9yIGdyb3VuZCBhbmQgc3VyZmFjZSB3YXRlciBjb250YW1pbmF0aW9uLiANClRoZSBnb2FsIG9mIHRoZSBpbml0aWF0aXZlIGlzIHRvIGRldGVybWluZSBpZiB0aGVyZSBhcmUgYW55IHNwYXRpYWwgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZXNlIGhhemFyZG91cyBsb2NhdGlvbnMgdGhhdCBoYXZlIHRoZSBwb3RlbnRpYWwgdG8gaW1wYWN0IGN1cnJlbnQgYW5kIGZ1dHVyZSByZXNpZGVudHMgb2YgdGhlIGFyZWEuIFRoZSBwcmltYXJ5IG9iamVjdGl2ZXMgb2YgdGhlIGluaXRhdGl2ZSBhcmUgdG86IGEpIGV4YW1pbmUgdGhlIGxvY2F0aW9uIG9mIGJyb3duZmllbGRzIGluIHRoZSBjb3VudHksIGIpIGRldGVybWluZSB3aGljaCB3YXRlcnNoZWRzIHdvdWxkIGJlIHByaW1hcmlseSBpbXBhY3RlZCwgYW5kIGMpIGFzY2VydGFpbiBpZiB0aGVyZSBpcyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGJyb3duZmllbGQgc2l0ZXMgYW5kIGFueSBwYXJ0aWN1bGFyIGRlbW9ncmFwaGljcyBpbiB0aGUgY291bnR5LiBXaXRoIHRoZXNlIHRocmVlIG9iamVjdGl2ZXMsIHRoZSBjb3VudHkgcGFydG5lcnMgbWF5IG1ha2UgZGF0YS1pbmZvcm1lZCBkZWNpc2lvbnMgdG8gYmVzdCBzdXBwb3J0IGFuZCBwcmlvcml0aXplIHByb2dyYW1zIHRoYXQga2VlcCBvdXIgY29tbXVuaXR5IGFuZCBlbnZpcm9ubWVudCBzYWZlLg0KDQpJbiB0aGlzIGV4ZXJjaXNlIHlvdSB3aWxsOg0KDQotICAgQ29udGludWUgd29ya2luZyB3aXRoIGdlb3Byb2Nlc3NpbmcgdG9vbHMNCi0gICBPYnRhaW4gYW5kIGltcG9ydCBkYXRhIGZyb20gZXh0ZXJuYWwgc291cmNlcw0KLSAgIExlYXJuIHRvIGxpbmsgdGFidWxhciBkYXRhDQotICAgUXVhbGl0YXRpdmVseSBjb21wYXJlIGRhdGFzZXRzDQoNClNvZnR3YXJlIHNwZWNpZmljIGRpcmVjdGlvbnMgY2FuIGJlIGZvdW5kIGZvciBlYWNoIHN0ZXAgYmVsb3cuIFBsZWFzZSBzdWJtaXQgdGhlIGFuc3dlciB0byB0aGUgcXVlc3Rpb25zIGFuZCB5b3VyIGZpbmFsIG1hcCBieSB0aGUgZHVlIGRhdGUuDQoNCiMjIFN0ZXAgT25lOiBUaGUgRGF0YQ0KDQpUaGUgZGF0YXNldHMgdXNlZCBpbiB0aGlzIGV4ZXJjaXNlIHdpbGwgYmUgZm91bmQgb24gdGhlIFtFeGVyY2lzZSA1XShodHRwczovL2dpdGh1Yi5jb20vY2hyaXNtZ2VudHJ5L0dJUzEtRXhlcmNpc2UtNSkgR2l0aHViIFBhZ2UsIHByZXZpb3VzIGV4ZXJjaXNlcyBzdWNoIGFzIFtFeGVyY2lzZSAyXShodHRwczovL2dpdGh1Yi5jb20vY2hyaXNtZ2VudHJ5L0dJUzEtRXhlcmNpc2UtMikgYW5kIFtFeGVyY2lzZSAzXShodHRwczovL2dpdGh1Yi5jb20vY2hyaXNtZ2VudHJ5L0dJUzEtRXhlcmNpc2UtMyksIGFuZCBhbHNvIGZyb20gdGhlIFtUZW5uZXNzZWUgR2VvZ3JhcGhpYyBJbmZvcm1hdGlvbiBDb3VuY2lsXShodHRwOi8vd3d3LnRuZ2lzLm9yZy9kYXRhLWNvbGxlY3Rpb25zLmh0bSkuICoqVE4gR0lTKiogbWFpbnRhaW5zIGEgbnVtYmVyIG9mIGRhdGFzZXRzIGluIHRoZWlyIGNvbGxlY3Rpb25zIHRoYXQgYXJlIHVzZWZ1bCBmb3IgcHJvamVjdHMgaW52b2x2aW5nIHRoZSBzdGF0ZSBvZiBUZW5uZXNzZWUuIA0KDQo8ZGV0YWlscz4NCjxzdW1tYXJ5PjxiaWc+VmlldyBEaXJlY3Rpb25zIGluIDxiPiBbQXJjR0lTIFByb117c3R5bGU9ImNvbG9yOiNmZjQ1MDAifSA8L2I+PC9iaWc+PC9zdW1tYXJ5Pg0KDQpBcyB3aXRoIHByZXZpb3VzIGV4ZXJjaXNlcyB5b3Ugc2hvdWxkIGJlZ2luIGJ5IGxhdW5jaGluZyBbQXJjR0lTIFByb117c3R5bGU9ImNvbG9yOiNmZjQ1MDAifSwgY3JlYXRpbmcgYSBuZXcgYmxhbmsgdGVtcGxhdGUsIGFuZCBjcmVhdGluZyBhIGZvbGRlciBmb3IgdGhpcyBzcGVjaWZpYyBleGVyY2lzZS4gWW91IHNob3VsZCBub3cgc2VlIHRoZSB0eXBpY2FsIHN0YXJ0aW5nIHNjcmVlbiB0aGF0IGdyZWV0ZWQgeW91IGluIGFsbCBvZiB0aGUgcHJldmlvdXMgZXhlcmNpc2VzLiBXaGlsZSBzb21lIG9mIHRoZSBkYXRhIGZvciB0aGlzIGV4ZXJjaXNlIHlvdSBtYXkgYWxyZWFkeSBoYXZlIGluIHByZXZpb3VzIGV4ZXJjaXNlIGZvbGRlcnMsIHlvdSB3aWxsIHN0YXJ0IHRoaXMgbGFiIGJ5IGRvd25sb2FkaW5nIGEgZGF0YXNldCBmcm9tICoqVE4gR0lTKiouIFdoaWxlIHRoZXkgbWFpbnRhaW4gYSBudW1iZXIgb2YgcXVhbGl0eSBjb2xsZWN0aW9ucywgeW91IHdpbGwgc3BlY2lmaWNhbGx5IGRvd25sb2FkIHRoZSBfc3RhdGV3aWRlIHdhdGVyc2hlZCBjb3ZlcmFnZSAoMTIgZGlnaXQgSHlkcm9sb2dpYyBVbml0IENvZGUpXyBmb3IgVGVubmVzc2VlLiBUaGlzIGluZm9ybWF0aW9uIGNhbiBiZSBmb3VuZCBhdCB0aGUgZm9sbG93aW5nIGxpbms6IFtodHRwOi8vd3d3LnRuZ2lzLm9yZy93YXRlci5odG1dKGh0dHA6Ly93d3cudG5naXMub3JnL3dhdGVyLmh0bSkuIE9uIHRoYXQgcGFnZSB5b3Ugd2lsbCBmaW5kIHRoZSBsaW5rIGZvciAqKiJEb3dubG9hZCBXYXRlcnNoZWQgQ292ZXJhZ2UiKiouIENsaWNrIHRoZSBsaW5rLCBhbmQgdXNpbmcgdGhlIGRvd25sb2FkIGJ1dHRvbiA8aW1nIHNyYz0gIkltYWdlcy9nb29nbGUtZHJpdmUtZG93bmxvYWQuanBnIiBhbHQ9Ikdvb2dsZSBEcml2ZSBEb3dubG9hZCBCdXR0b24iIHdpZHRoID0gIjIwIiBoZWlnaHQgPSAiMjAiPiBpbiB0aGUgdXBwZXItcmlnaHQgY29ybmVyLCBzYXZlIHRoZSBfdG5fd2JkXyB6aXAgZmlsZSB0byB5b3VyIHByb2plY3QgZm9sZGVyLg0KDQo8cCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0gIkltYWdlcy90bmdpcy13ZWJzaXRlLnBuZyIgYWx0PSJUTiBHSVMgV2F0ZXIgRGF0YSBEb3dubG9hZCIgc3R5bGU9IndpZHRoOjEwMCUiPjwvcD4NCg0KT25jZSB5b3UgaGF2ZSBkb3dubG9hZGVkIHRoZSBmaWxlLCBuYXZpZ2F0ZSB0byB0aGUgc2F2ZWQgbG9jYXRpb24gdG8gdW56aXAgdGhlIGZpbGUuIFdpdGhpbiB0aGUgdW56aXBwZWQgZm9sZGVyIHlvdSB3aWxsIGZpbmQgdGhyZWUgYWRkaXRpb25hbCBmb2xkZXJzIHRpdGxlZDoNCg0KLSB0bl84ZGlnX2h1Yw0KLSB0bl8xMmRpZ19odWMNCi0gdG5fMjUwa19odWMNCg0KVGhlc2UgYXJlIHdhdGVyc2hlZCBmaWxlcyBhdCB2YXJ5aW5nIGxldmVscyBvZiBkZXRhaWwuIEZvciBoeWRyb2xvZ2ljIHVuaXRzIHlvdSBhcmUgbG9va2luZyBmb3Igb25lIHdpdGggdGhlIGxhcmdlc3QgbnVtYmVyIG9mIGRpZ2l0cyB0byBnZXQgdGhlIGxhcmdlc3Qgc2NhbGUgZGF0YS4gU28gZm9yIHRoaXMgZXhlcmNpc2UgeW91IHdpbGwgdW56aXAgdGhlICoqdG5fMTJkaWdfaHVjKiogZGF0YXNldC4NCg0KPHAgYWxpZ249ImNlbnRlciI+PGltZyBzcmM9ICJJbWFnZXMvc2Vjb25kLXVuemlwLmpwZyIgYWx0PSJ0bl8xMmRpZ19odWMuemlwIGV4dHJhY3QiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L3A+DQoNCkZpbmFsbHksIHdpdGggdGhhdCBmaW5hbCBmb2xkZXIgZXh0cmFjdGVkIHlvdSB3aWxsIGZpbmQgYSBmb2xkZXIgdGl0bGVkIF9oeWRyb2xvZ2ljX3VuaXRzXyB0aGF0IHdpbGwgY29udGFpbiBhIHNoYXBlZmlsZSBuYW1lZCAqKndiZGh1MTJfYV90bi5zaHAqKiB0aGF0IHdpbGwgYmUgdXNlZCBpbiB0aGlzIGV4ZXJjaXNlLiBUaGlzIGlzIHRoZSBwb2x5Z29uIGZpbGUgcmVwcmVzZW50aW5nIHRoZSAxMiBkaWdpdCBoeWRyb2xvZ2ljIHVuaXQgY29kZXMgZm9yIHRoZSBlbnRpcmUgc3RhdGUgb2YgVGVubmVzc2VlLg0KDQpOZXh0LCB5b3Ugd2lsbCBuZWVkIHRoZSBfdG9ybmFkb19kYXRhXyBmaWxlIGZyb20gRXhlcmNpc2UgMiBhbmQgdGhlIF9jZW5zdXNfdHJhY3RzXyBkYXRhIGZyb20gRXhlcmNpc2UgMy4gWW91IGhhdmUgYSBmZXcgb3B0aW9ucyBmb3Igb2J0YWluaW5nIHRoaXMgZGF0YS4gWW91IGNhbiBkb3dubG9hZCB0aGUgZGF0YSBhZ2FpbiAoYnV0IHRoaXMgdGltZSB0byB0aGUgbmV3IHByb2plY3QgZm9sZGVyKSwgeW91IGNhbiBuYXZpZ2F0ZSB0byB0aGUgRXhlcmNpc2UgMiBhbmQgRXhlcmNpc2UgMyBwcm9qZWN0IGZvbGRlcnMsIHJlc3BlY3RpdmVseSwgb24geW91ciBjb21wdXRlciBhbmQgY29weSB0aGUgemlwIGZpbGVzIHRvIHRoZSBFeGVyY2lzZSA1IHByb2plY3QgZm9sZGVyLCBvciB5b3UgY2FuIGNvcHkgdGhlIGRhdGEgb3ZlciB1c2luZyB0aGUgY2F0YWxvZyBwYW5lIGluIFtBcmNHSVMgUHJvXXtzdHlsZT0iY29sb3I6I2ZmNDUwMCJ9LiBXaGlsZSB0aGUgZmlyc3QgdHdvIG9wdGlvbnMgYXJlIHJlbGF0aXZlbHkgc3RyYWlnaHQgZm9yd2FyZCwgaXQgaXMgaW1wb3J0YW50IHRvIGxlYXJuIGhvdyB0byBuYXZpZ2F0ZSBhbmQgdXNlIHRoZSBjYXRhbG9nIGluIEFyY0dJUy4gDQoNCk9uIHRoZSBfVmlld18gdGFiLCBjbGljayB0aGUgQ2F0YWxvZyBQYW5lIGJ1dHRvbiA8aW1nIHNyYz0gIkltYWdlcy9jYXRhbG9nLXBhbmUtYnV0dG9uLmpwZyIgYWx0PSJDYXRhbG9uZyBQYW5lIEJ1dHRvbiIgd2lkdGggPSAiMTQiIGhlaWdodCA9ICIyMCI+IHRvIG9wZW4gdGhlIENhdGFsb2cgV2luZG93IFBhbmUgb24gdGhlIHJpZ2h0IHNpZGUgb2YgdGhlIHNjcmVlbi4gT24gdGhlIHByb2plY3QgdGFiLCByaWdodC1jbGljayBvbiB0aGUgZm9sZGVycyBvcHRpb24gYW5kIGNsaWNrICJBZGQgRm9sZGVyIENvbm5lY3Rpb24uIEluIHRoZSByZXN1bHRpbmcgd2luZG93IG5hdmlnYXRlIHRvIHRoZSBmb2xkZXIgeW91IHdvdWxkIGxpa2UgdG8gY29ubmVjdCB0byBhbmQgc2luZ2xlLWNsaWNrIHRoZSBmb2xkZXIgdG8gc2VsZWN0IGl0LiBZb3UgZG9uJ3Qgd2FudCB0byBkb3VibGUtY2xpY2sgaW50byB0aGUgZm9sZGVyLiBZb3Ugc2hvdWxkIHNlZSB0aGUgbmFtZSBvZiB0aGUgZm9sZGVyIGFwcGVhciBhdCB0aGUgYm90dG9tIG9mIHRoZSB3aW5kb3cgYW5kIHRoZSBPSyBidXR0b24gc2hvdWxkIGJlIGF2YWlsYWJsZS4NCg0KPHAgYWxpZ249ImNlbnRlciI+PGltZyBzcmM9ICJJbWFnZXMvY2F0YWxvZy1wYW5lLXdpbmRvd3MucG5nIiBhbHQ9IkFjY2Vzc2luZyBDYXRhbG9nIFBhbmUiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L3A+DQoNCk9uY2UgeW91IGhhdmUgY29ubmVjdGVkIHRvIHRoZSBhZGRpdGlvbmFsIGZvbGRlcnMgeW91IHdhbnQgdG8gdXNlIGluIGNvbmp1bmN0aW9uIHdpdGggdGhpcyBwcm9qZWN0IHlvdSBjYW4gbmF2aWdhdGUgdG8gdGhlbSB3aXRoaW4gdGhlIF9Gb2xkZXJzXyBsaW5rIGluIHRoZSBDYXRhbG9nIFBhbmUuIFdoaWxlIHlvdSBjb3VsZCBhZGQgZGF0YSBkaXJlY3RseSBmcm9tIHRoZSBvdGhlciBmb2xkZXJzLCB0aGUgYmVzdCBwcmFjdGljZSBtaWdodCBiZSB0byBjb3B5IHRoZSBkYXRhIGZyb20gb25lIHByb2plY3QgdG8gYW5vdGhlci4gSWYgZm9yIGV4YW1wbGUgeW91IHBsYW4gdG8gYWx0ZXIgdGhlIGRhdGEgdGhlbiB1c2luZyBpdCBkaXJlY3RseSBmcm9tIHRoZSBwcmV2aW91cyBmb2xkZXIgd291bGQgYWx0ZXIgaXQgdGhlcmUgYXMgd2VsbC4gVGhpcyBjb3VsZCBjYXVzZSBmdXR1cmUgaXNzdWVzIHdoZW4gcmV0dXJuaW5nIHRvIHRoYXQgcHJvamVjdC4gRm9yIHRoaXMgZXhlcmNpc2UgeW91IGNhbiBuYXZpZ2F0ZSB0byB0aGUgRXhlcmNpc2UgMiBmb2xkZXIgYW5kIGNvcHkgdGhlIF90b3JuYWRvX2RhdGFfIGZpbGUgYW5kIHBhc3RlIGl0IGluIHRoZSBFeGVyY2lzZSA1IGZvbGRlci4gVGhpcyBpcyB0aGUgc2FmZXN0IHdheSB0byBtb3ZlIGRhdGEgc3VjaCBhcyBzaGFwZWZpbGVzIG9yIGdlb2RhdGFiYXNlcy4gQmVjYXVzZSB0aGUgdmFyaW91cyBkYXRhIHR5cGVzIGNvbnRhaW4gbnVtZXJvdXMgaW5kaXZpZHVhbCBmaWxlcyB0byBtYWtlIHVwIGEgZGF0YXNldCwgY2F0YWxvZyB3aWxsIGNvcHkvbW92ZSB0aGVtIGFsbCBjb3JyZWN0bHkuIElmIHlvdSB0cmllZCB0byBtb3ZlIHRoZW0gdXNpbmcgRmlsZSBFeHBsb3JlciBhbmQgbWlzc2VkIG9uZSBvZiB0aGUgZmlsZXMgYXNzb2NpYXRlZCB3aXRoIHRoYXQgZGF0YSBpdCBtaWdodCBub3Qgd29yayBhcHByb3ByaWF0ZWx5LiBTbyBmb3IgRXhlcmNpc2UgNSwgeW91IHdpbGwgbmVlZCB0byBjb3B5IHRoZSBfdG9ybmFkb19kYXRhXyBhbmQgX21vbnRjb190cmFjdHNfIGRhdGEgZnJvbSBleGVyY2lzZXMgdHdvIGFuZCB0aHJlZSByZXNwZWN0aXZlbHkuDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxkaXYgY2xhc3M9Inpvb20iPjxpbWcgc3JjPSAiSW1hZ2VzL2NhdGFsb2ctY29weS1wYXN0ZS5wbmciIGFsdD0iQ29weSBhbmQgUGFzdGUgRGF0YSBpbiBDYXRhbG9nIFBhbmUiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L2Rpdj48L3A+DQoNCkZpbmFsbHksIHlvdSB3aWxsIG5lZWQgdG8gZG93bmxvYWQgdGhlICoqQnJvd25maWVsZHMqKiBhbmQgKipEZW1vZ3JhcGhpY3MqKiBkYXRhIGZyb20gdGhlIFtFeGVyY2lzZSA1LCBHaXRIdWIgRGF0YV0oaHR0cHM6Ly9naXRodWIuY29tL2NocmlzbWdlbnRyeS9HSVMxLUV4ZXJjaXNlLTUvdHJlZS9tYWluL0RhdGEpIHBhZ2UuIFNhdmUgYm90aCBpbiB5b3VyIEV4ZXJjaXNlIDUgcHJvamVjdCBmb2xkZXIgYW5kIHVuemlwIHRoZSAqKmJyb3duZmllbGRzLnppcCoqIGZpbGUgdG8gYWNjZXNzIHRoZSBkYXRhc2V0Lg0KDQo8YmlnPjxiPlF1ZXN0aW9uIE5vLiAxPC9iPjwvYmlnPjxicj4NClVzaW5nICoqRmlsZSBFeHBsb3JlcioqLCBleGFtaW5lIHRoZSBkYXRhc2V0IGNvbnRhaW5lZCBpbiB0aGUgX2Jyb3duZmllbGRzLnppcF8gZmlsZSBhbmQgYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb246DQo8YmxvY2txdW90ZT4NCldoYXQgaXMgdGhlIGNvbW1vbiBuYW1lIG9mIHRoZSBleHRyYWN0ZWQgZmlsZXM/IEhvdyBtYW55IGFyZSB0aGVyZT8gV2hhdCBhcmUgdGhlIHZhcmlvdXMgZmlsZSBleHRlbnNpb25zPw0KPC9ibG9ja3F1b3RlPg0KPHNtYWxsPlRoZSBsaWJyYXJ5IG9mIENvbmdyZXNzIGhhcyBhIGdyZWF0IGRlc2NyaXB0aW9uIG9mIHRoZSB2YXJpb3VzIGV4dGVuc2lvbnMgW2hlcmVdKGh0dHBzOi8vd3d3LmxvYy5nb3YvcHJlc2VydmF0aW9uL2RpZ2l0YWwvZm9ybWF0cy9mZGQvZmRkMDAwMjgwLnNodG1sKS48L3NtYWxsPg0KPC9kZXRhaWxzPg0KPGhyPjwvaHI+DQoNCjxkZXRhaWxzPg0KPHN1bW1hcnk+PGJpZz5WaWV3IGRpcmVjdGlvbnMgaW4gPGI+IFtRR0lTXXtzdHlsZT0iY29sb3I6ICMwMDY0MDAifSA8L2I+PC9iaWc+PC9zdW1tYXJ5Pg0KDQpBcyB3aXRoIHByZXZpb3VzIGV4ZXJjaXNlcyB5b3Ugc2hvdWxkIGJlZ2luIGJ5IGxhdW5jaGluZyBbUUdJU117c3R5bGU9ImNvbG9yOiAjMDA2NDAwIn0sIGNyZWF0aW5nIGEgbmV3IGVtcHR5IHByb2plY3QsIGFuZCBjcmVhdGluZyBhIHByb2plY3QgZm9sZGVyIGZvciB0aGlzIHNwZWNpZmljIGV4ZXJjaXNlLiBZb3Ugc2hvdWxkIG5vdyBzZWUgdGhlIHR5cGljYWwgc3RhcnRpbmcgc2NyZWVuIHRoYXQgZ3JlZXRlZCB5b3UgaW4gYWxsIG9mIHRoZSBwcmV2aW91cyBleGVyY2lzZXMuIFdoaWxlIHNvbWUgb2YgdGhlIGRhdGEgZm9yIHRoaXMgZXhlcmNpc2UgeW91IG1heSBhbHJlYWR5IGhhdmUgaW4gcHJldmlvdXMgZXhlcmNpc2UgZm9sZGVycywgeW91IHdpbGwgc3RhcnQgdGhpcyBsYWIgYnkgZG93bmxvYWRpbmcgYSBkYXRhc2V0IGZyb20gKipUTiBHSVMqKi4gV2hpbGUgdGhleSBtYWludGFpbiBhIG51bWJlciBvZiBxdWFsaXR5IGNvbGxlY3Rpb25zLCB5b3Ugd2lsbCBzcGVjaWZpY2FsbHkgZG93bmxvYWQgdGhlIF9zdGF0ZXdpZGUgd2F0ZXJzaGVkIGNvdmVyYWdlICgxMiBkaWdpdCBIeWRyb2xvZ2ljIFVuaXQgQ29kZSlfIGZvciBUZW5uZXNzZWUuIFRoaXMgaW5mb3JtYXRpb24gY2FuIGJlIGZvdW5kIGF0IHRoZSBmb2xsb3dpbmcgbGluazogW2h0dHA6Ly93d3cudG5naXMub3JnL3dhdGVyLmh0bV0oaHR0cDovL3d3dy50bmdpcy5vcmcvd2F0ZXIuaHRtKS4gT24gdGhhdCBwYWdlIHlvdSB3aWxsIGZpbmQgdGhlIGxpbmsgZm9yICoqIkRvd25sb2FkIFdhdGVyc2hlZCBDb3ZlcmFnZSIqKi4gQ2xpY2sgdGhlIGxpbmssIGFuZCB1c2luZyB0aGUgZG93bmxvYWQgYnV0dG9uIDxpbWcgc3JjPSAiSW1hZ2VzL2dvb2dsZS1kcml2ZS1kb3dubG9hZC5qcGciIGFsdD0iR29vZ2xlIERyaXZlIERvd25sb2FkIEJ1dHRvbiIgd2lkdGggPSAiMjAiIGhlaWdodCA9ICIyMCI+IGluIHRoZSB1cHBlci1yaWdodCBjb3JuZXIsIHNhdmUgdGhlIF90bl93YmRfIHppcCBmaWxlIHRvIHlvdXIgcHJvamVjdCBmb2xkZXIuDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxpbWcgc3JjPSAiSW1hZ2VzL3RuZ2lzLXdlYnNpdGUucG5nIiBhbHQ9IlROIEdJUyBXYXRlciBEYXRhIERvd25sb2FkIiBzdHlsZT0id2lkdGg6MTAwJSI+PC9wPg0KDQpPbmNlIHlvdSBoYXZlIGRvd25sb2FkZWQgdGhlIGZpbGUsIG5hdmlnYXRlIHRvIHRoZSBzYXZlZCBsb2NhdGlvbiB0byB1bnppcCB0aGUgZmlsZS4gV2l0aGluIHRoZSB1bnppcHBlZCBmb2xkZXIgeW91IHdpbGwgZmluZCB0aHJlZSBhZGRpdGlvbmFsIGZvbGRlcnMgdGl0bGVkOg0KDQotIHRuXzhkaWdfaHVjDQotIHRuXzEyZGlnX2h1Yw0KLSB0bl8yNTBrX2h1Yw0KDQpUaGVzZSBhcmUgd2F0ZXJzaGVkIGZpbGVzIGF0IHZhcnlpbmcgbGV2ZWxzIG9mIGRldGFpbC4gRm9yIGh5ZHJvbG9naWMgdW5pdHMgeW91IGFyZSBsb29raW5nIGZvciBvbmUgd2l0aCB0aGUgbGFyZ2VzdCBudW1iZXIgb2YgZGlnaXRzIHRvIGdldCB0aGUgbGFyZ2VzdCBzY2FsZSBkYXRhLiBTbyBmb3IgdGhpcyBleGVyY2lzZSB5b3Ugd2lsbCB1bnppcCB0aGUgKip0bl8xMmRpZ19odWMqKiBkYXRhc2V0Lg0KDQo8cCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0gIkltYWdlcy9zZWNvbmQtdW56aXAuanBnIiBhbHQ9InRuXzEyZGlnX2h1Yy56aXAgZXh0cmFjdCIgc3R5bGU9IndpZHRoOjEwMCUiPjwvcD4NCg0KRmluYWxseSwgd2l0aCB0aGF0IGZpbmFsIGZvbGRlciBleHRyYWN0ZWQgeW91IHdpbGwgZmluZCBhIGZvbGRlciB0aXRsZWQgX2h5ZHJvbG9naWNfdW5pdHNfIHRoYXQgd2lsbCBjb250YWluIGEgc2hhcGVmaWxlIG5hbWVkICoqd2JkaHUxMl9hX3RuLnNocCoqIHRoYXQgd2lsbCBiZSB1c2VkIGluIHRoaXMgZXhlcmNpc2UuIFRoaXMgaXMgdGhlIHBvbHlnb24gZmlsZSByZXByZXNlbnRpbmcgdGhlIDEyIGRpZ2l0IGh5ZHJvbG9naWMgdW5pdCBjb2RlcyBmb3IgdGhlIGVudGlyZSBzdGF0ZSBvZiBUZW5uZXNzZWUuDQoNCk5leHQsIHlvdSB3aWxsIG5lZWQgdGhlIF90b3JuYWRvX2RhdGFfIGZpbGUgZnJvbSBFeGVyY2lzZSAyIGFuZCB0aGUgX2NlbnN1c190cmFjdHNfIGRhdGEgZnJvbSBFeGVyY2lzZSAzLiBZb3UgaGF2ZSBhIGZldyBvcHRpb25zIGZvciBvYnRhaW5pbmcgdGhpcyBkYXRhLiBZb3UgY2FuIGRvd25sb2FkIHRoZSBkYXRhIGFnYWluIChidXQgdGhpcyB0aW1lIHRvIHRoZSBuZXcgcHJvamVjdCBmb2xkZXIpLCB5b3UgY2FuIG5hdmlnYXRlIHRvIHRoZSBFeGVyY2lzZSAyIGFuZCBFeGVyY2lzZSAzIHByb2plY3QgZm9sZGVycywgcmVzcGVjdGl2ZWx5LCBvbiB5b3VyIGNvbXB1dGVyIGFuZCBjb3B5IHRoZSB6aXAgZmlsZXMgdG8gdGhlIEV4ZXJjaXNlIDUgcHJvamVjdCBmb2xkZXIsIG9yIHlvdSBjYW4gY29weSB0aGUgZGF0YSBvdmVyIHVzaW5nIHRoZSBfYnJvd3NlciB3aW5kb3dfIGluIFtRR0lTXXtzdHlsZT0iY29sb3I6ICMwMDY0MDAifS4gV2hpbGUgdGhlIGZpcnN0IHR3byBvcHRpb25zIGFyZSByZWxhdGl2ZWx5IHN0cmFpZ2h0IGZvcndhcmQsIGl0IGlzIGltcG9ydGFudCB0byBiZSBjb25maWRlbnQgbmF2aWdhdGluZyBhbmQgdXNpbmcgdGhlIGJyb3dzZXIgaW4gUUdJUy4NCg0KSWYgeW91IGNyZWF0ZWQgYSAiZmF2b3JpdGVzIiBmb2xkZXIgeW91IHdpbGwgbW9zdCBsaWtlbHkgbmF2aWdhdGUgd2l0aGluIHRoYXQgbG9jYXRpb24sIGhvd2V2ZXIsIGlmIHlvdSBoYXZlbid0IGNyZWF0ZWQgYSBmYXZvcml0ZSBmb2xkZXIgeW91IHdpbGwgc2VhcmNoIHRocm91Z2ggeW91ciBkcml2ZXMgZm9yIHRoZSBfdG9ybmFkb19kYXRhXyBmaWxlIGZyb20gRXhlcmNpc2UgMi4gT25jZSB5b3UgbG9jYXRlIHRoZSBmaWxlLCByaWdodC9DUlRMIGNsaWNrIG9uIHRoZSBmaWxlIGFuZCBzZWxlY3QgKipFeHBvcnQgTGF5ZXIgPiBUbyBGaWxlLi4uKiouIEluIHRoZSByZXN1bHRpbmcgd2luZG93IHNlbGVjdCBfRVNSSSBTaGFwZWZpbGVfIGFzIHRoZSAiRm9ybWF0IiwgZm9yIHRoZSAiRmlsZSBuYW1lIiBjbGljayBvbiB0aGUgYnJvd3NlIGJ1dHRvbiA8aW1nIHNyYz0gIkltYWdlcy9xZ2lzLWZpbGUtbG9jYXRpb24tYnV0dG9uLmpwZyIgYWx0PSJCcm93c2UgTG9jYXRpb24gQnV0dG9uIiB3aWR0aCA9ICIyMCIgaGVpZ2h0ID0gIjIwIj4gYW5kIGdpdmUgaXQgYSBmaWxlIG5hbWUgYW5kIHNhdmUgaXQgdG8geW91ciBFeGVyY2lzZSA1IHByb2plY3QgZm9sZGVyLiBJZiB5b3UgY2hlY2sgdGhlICJBZGQgU2F2ZWQgRmlsZSB0byBNYXAiIGJ1dHRvbiBhbmQgY2xpY2sgT0sgdGhlIGZpbGUgd2lsbCBiZSBhZGRlZCB0byB5b3VyIGxheWVycy4gDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxkaXYgY2xhc3M9Inpvb20iPjxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtYnJvd3Nlci5wbmciIGFsdD0iRXhwb3J0IGZpbGUgZnJvbSBCcm93c2VyIiBzdHlsZT0id2lkdGg6MTAwJSI+PC9kaXY+PC9wPg0KDQpSZXBlYXQgdGhpcyBwcm9jZXNzIGZvciB0aGUgX2NlbnN1c190cmFjdHNfIGRhdGEgZnJvbSBFeGVyY2lzZSAzLiBXaGlsZSB5b3UgY291bGQgYWRkIGRhdGEgZGlyZWN0bHkgZnJvbSB0aGUgb3RoZXIgZm9sZGVycywgdGhlIGJlc3QgcHJhY3RpY2UgbWlnaHQgYmUgdG8gZXhwb3J0IHRoZSBkYXRhIGZyb20gb25lIHByb2plY3QgdG8gYW5vdGhlci4gSWYgZm9yIGV4YW1wbGUgeW91IHBsYW4gdG8gYWx0ZXIgdGhlIGRhdGEgdGhlbiB1c2luZyBpdCBkaXJlY3RseSBmcm9tIHRoZSBwcmV2aW91cyBmb2xkZXIgd291bGQgYWx0ZXIgaXQgdGhlcmUgYXMgd2VsbC4gVGhpcyBjb3VsZCBjYXVzZSBmdXR1cmUgaXNzdWVzIHdoZW4gcmV0dXJuaW5nIHRvIHRoYXQgcHJvamVjdC4gV2l0aCB0aGVzZSB0d28gZmlsZXMgYWRkZWQgdG8geW91ciBsYXllcnMgeW91IG9ubHkgbmVlZCB0byBkb3dubG9hZCB0aGUgKipCcm93bmZpZWxkcyoqIGFuZCAqKkRlbW9ncmFwaGljcyoqIGRhdGEgZnJvbSB0aGUgW0V4ZXJjaXNlIDUsIEdpdEh1YiBEYXRhXShodHRwczovL2dpdGh1Yi5jb20vY2hyaXNtZ2VudHJ5L0dJUzEtRXhlcmNpc2UtNS90cmVlL21haW4vRGF0YSkgcGFnZS4gU2F2ZSBib3RoIGluIHlvdXIgRXhlcmNpc2UgNSBwcm9qZWN0IGZvbGRlciBhbmQgdW56aXAgdGhlICoqYnJvd25maWVsZHMuemlwKiogZmlsZSB0byBhY2Nlc3MgdGhlIGRhdGFzZXQuDQoNCjxiaWc+PGI+UXVlc3Rpb24gTm8uIDE8L2I+PC9iaWc+PGJyPg0KVXNpbmcgKipGaWxlIEV4cGxvcmVyL0ZpbmRlcioqLCBleGFtaW5lIHRoZSBkYXRhc2V0IGNvbnRhaW5lZCBpbiB0aGUgX2Jyb3duZmllbGRzLnppcF8gZmlsZSBhbmQgYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb246DQo8YmxvY2txdW90ZT4NCldoYXQgaXMgdGhlIGNvbW1vbiBuYW1lIG9mIHRoZSBleHRyYWN0ZWQgZmlsZXM/IEhvdyBtYW55IGFyZSB0aGVyZT8gV2hhdCBhcmUgdGhlIHZhcmlvdXMgZmlsZSBleHRlbnNpb25zPw0KPC9ibG9ja3F1b3RlPg0KPHNtYWxsPlRoZSBsaWJyYXJ5IG9mIENvbmdyZXNzIGhhcyBhIGdyZWF0IGRlc2NyaXB0aW9uIG9mIHRoZSB2YXJpb3VzIGV4dGVuc2lvbnMgW2hlcmVdKGh0dHBzOi8vd3d3LmxvYy5nb3YvcHJlc2VydmF0aW9uL2RpZ2l0YWwvZm9ybWF0cy9mZGQvZmRkMDAwMjgwLnNodG1sKS48L3NtYWxsPg0KDQo8L2RldGFpbHM+DQo8aHI+PC9ocj4NCg0KPGRldGFpbHM+PHN1bW1hcnk+PGJpZz5WaWV3IGRpcmVjdGlvbnMgaW4gPGI+IFtSXXtzdHlsZT0iY29sb3I6ICM2NDk1RUQifSA8L2I+PC9zcGFuPjwvYmlnPjwvc3VtbWFyeT4NCkJlZm9yZSB5b3UgYmVnaW4sIHlvdSB3aWxsIG5lZWQgdG8gb3BlbiB0aGUgW0V4NSBDb2xhYiBOb3RlYm9va10oaHR0cHM6Ly9naXRodWIuY29tL2NocmlzbWdlbnRyeS9HSVMxLUV4ZXJjaXNlLTUvYmxvYi9tYWluL0dJUzFfRVg1LmlweW5iKSBhbmQgaW5zZXJ0ICoqdG9jb2xhYioqIGFmdGVyIF9naXRodWJfIGluIHRoZSBVUkwgdG8gb3BlbiBpbiB0aGUgX0NvbGFiIEVudmlyb25tZW50Xy4gQXMgeW91IGhhdmUgc2VlbiBiZWZvcmUsIFtSXXtzdHlsZT0iY29sb3I6ICM2NDk1RUQifSByZXF1aXJlcyB2YXJpb3VzIHBhY2thZ2VzIHRvIGNvbXBsZXRlIGNlcnRhaW4gYW5hbHlzZXMuIEluIHRoaXMgZXhlcmNpc2UgeW91IHdpbGwgYmUgdXNpbmcgYSBsYXJnZSBudW1iZXIgb2YgcGFja2FnZXMgaW5jbHVkaW5nOiAqKmdvb2dsZWRyaXZlLCB0aWR5dmVyc2UsIGdnc24sIGNvd3Bsb3QsIG1hcHMsIG1hcHByb2osIHJhc3Rlciwgcmdlb3MsIHJnZGFsLCBzcCwgc2YsIGJpc2NhbGUqKi4gRWFjaCBvZiB0aGVzZSBwYWNrYWdlcyBhbHNvIGNvbnRhaW4gdmFyaW91cyBkZXBlbmRlbmNpZXMgc28gaXQgd2lsbCB0YWtlIGEgd2hpbGUgdG8gbG9hZC4gSW4gcHJldmlvdXMgZXhlcmNpc2VzIHlvdSBpbnN0YWxsZWQgYW5kIGxvYWRlZCBwYWNrYWdlcyBpbmRpdmlkdWFsbHkuIFRoaXMgcmVxdWlyZXMgdHdvIGxpbmVzIG9mIGNvZGUgZm9yIGVhY2ggcGFja2FnZS4gVGhlcmVmb3JlIHRoaXMgZXhlcmNpc2Ugd291bGQgYmVnaW4gd2l0aCB0d2VudHktZm91ciBsaW5lcyB0byBpbnN0YWxsIGFuZCBsb2FkIHRoZSBuZWNlc3NhcnkgcGFja2FnZXMuIFNvIGluIHRoaXMgZXhlcmNpc2UgeW91IHdpbGwgbGVhcm4gdG8gaW5zdGFsbCBhbmQgbG9hZCB0aGUgcGFja2FnZXMgaW4gYSB0aHJlZSBsaW5lIHNjcmlwdC4gVGhlIGZpcnN0IGxpbmUgbGlzdHMgdGhlIHBhY2thZ2VzLCB0aGUgc2Vjb25kIGxpbmUgaW5zdGFsbHMgYWxsIHBhY2thZ2VzLCBhbmQgdGhlIHRoaXJkIGxpbmUgbG9hZHMgdGhlbS4gSW4gbGF0ZXIgZXhlcmNpc2VzIHlvdSB3aWxsIGxlYXJuIHRvIHVzZSBhIGxpYnJhcnkgbWFuYWdlbWVudCBwYWNrYWdlIHRvIGNoZWNrIGZvciBsaWJyYXJpZXMgb24geW91ciBjb21wdXRlciwgaW5zdGFsbCB0aGVtIGlmIG5lY2Vzc2FyeSwgYW5kIGxvYWQgdGhlIHBhY2thZ2VzIG5lY2Vzc2FyeSBmb3IgdGhlIHByb2plY3QuIEZvciB0aGlzIGV4ZXJjaXNlIHlvdSB3aWxsIHVzZSB0aGUgZm9sbG93aW5nIHNjcmlwdDoNCg0KYGBge3IgbG9hZCBwYWNrYWdlcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobyA9IFRSVUV9DQpwYWNrYWdlczwtYygnZ29vZ2xlZHJpdmUnLCd0aWR5dmVyc2UnLCdnZ3NuJywnY293cGxvdCcsJ21hcHMnLCdtYXBwcm9qJywNCiAgICAgICAgICAgICdyYXN0ZXInLCdyZ2VvcycsJ3JnZGFsJywnc3AnLCdzZicsJ2Jpc2NhbGUnKQ0Kc2FwcGx5KHBhY2thZ2VzLCBpbnN0YWxsLnBhY2thZ2VzLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQpzYXBwbHkocGFja2FnZXMsIHJlcXVpcmUsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCmBgYA0KDQpBcyB3aXRoIFtFeGVyY2lzZSAzXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS0zLykgdGhlIGB0aWdyaXNgIHBhY2thZ2UgbmVlZHMgdG8gYmUgbG9hZGVkIHNlcGFyYXRlbHkgZnJvbSBvdGhlciBwYWNrYWdlcyB3aXRoIHRoZSBmb2xsb3dpbmcgc2NyaXB0Og0KDQpgYGB7ciBsb2FkIHRpZ3JpcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCd3YWxrZXJrZS90aWdyaXMnKQ0KbGlicmFyeSgndGlncmlzJykNCmBgYA0KDQpUaGUgZGF0YXNldHMgbmVlZGVkIGZvciB0aGlzIGV4ZXJjaXNlIGluY2x1ZGU6IGNlbnN1cyB0cmFjdHMgZnJvbSBbRXhlcmNpc2UgM10oaHR0cHM6Ly9naXRodWIuY29tL2NocmlzbWdlbnRyeS9HSVMxLUV4ZXJjaXNlLTMvdHJlZS9tYWluL0RhdGEpLCB3YXRlcnNoZWRzIGRhdGEgZnJvbSBbVE4gR0lTXShodHRwOi8vd3d3LnRuZ2lzLm9yZy93YXRlci5odG0pLCBicm93bmZpZWxkcyBpbmZvcm1hdGlvbiBhbmQgZGVtb2dyYXBoaWNzIGRhdGEgZnJvbSB0aGlzIFtleGVyY2lzZV0oaHR0cHM6Ly9naXRodWIuY29tL2NocmlzbWdlbnRyeS9HSVMxLUV4ZXJjaXNlLTUvdHJlZS9tYWluL0RhdGEpLiBBcyB3aXRoIHByZXZpb3VzIGV4ZXJjaXNlcyBhbGwgb2YgdGhlIGRhdGEgZm9yIHRoaXMgbGFiIHdpbGwgYmUgYWJsZSB0byBiZSBkb3dubG9hZGVkIGRpcmVjdCBmcm9tIGVpdGhlciBhIFtHaXRIdWIgUGFnZV0oaHR0cHM6Ly9naXRodWIuY29tL2NocmlzbWdlbnRyeS9HSVMxLUV4ZXJjaXNlLTUpIG9yIGZyb20gYSBwdWJsaWMgd2Vic2l0ZS4gVGhlIGRhdGEgZnJvbSB0aGUgVE4gR0lTIGlzIHN0b3JlZCBpbiBhIEdvb2dsZSBEcml2ZSBmb2xkZXIuIE1vc3QgY2xvdWQgc3RvcmFnZSBwbGF0Zm9ybXMgaGF2ZSB1bmlxdWUgZGF0YSBzdHJ1Y3R1cmUgdGhhdCByZXF1aXJlIG1vcmUgZGV0YWlsZWQgZG93bmxvYWQgaW5mb3JtYXRpb24gdGhhbiBhIHNpbXBsZSBcKi5jc3YgYmVpbmcgc3RvcmVkIG9uIGEgd2VicGFnZS4gU28gdG8gZG93bmxvYWQgYSBmaWxlIGZyb20gR29vZ2xlIERyaXZlIHlvdSB3aWxsIHVzZSB0aGUgYGdvb2dsZWRyaXZlYCBwYWNrYWdlIHRoYXQgd2FzIGluc3RhbGxlZCBpbiB0aGUgbGlzdCBvZiBwYWNrYWdlcyBhYm92ZS4NCg0KVG8gYXZvaWQgY29ubmVjdGluZyB5b3VyIG93biBHb29nbGUgY3JlZGllbnRpYWxzIHlvdSB3aWxsIGJlZ2luIGJ5IHVzaW5nIHRoZSBgZHJpdmVfZGVhdXRoYCBmdW5jdGlvbiB3aGljaCBzdXNwZW5kcyBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzLiBEZXBlbmRpbmcgb24geW91ciB1c2Ugb2YgR29vZ2xlIERyaXZlIHdpdGhpbiBSIHlvdSBtYXkgbmVlZCB0byBwcm92aWRlIHlvdXIgbG9naW4gY3JlZGVudGlhbHMgb3IgYW4gYWNjZXNzIHRva2VuLiBJZiB5b3UgbmF2aWdhdGUgdG8gW2h0dHA6Ly93d3cudG5naXMub3JnL3dhdGVyLmh0bV0oaHR0cDovL3d3dy50bmdpcy5vcmcvd2F0ZXIuaHRtKSB5b3Ugd2lsbCBmaW5kIHRoZSBsaW5rIGZvciAqKiJEb3dubG9hZCBXYXRlcnNoZWQgQ292ZXJhZ2UiKiouIA0KDQo8cCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0gIkltYWdlcy90bmdpcy13ZWJzaXRlLnBuZyIgYWx0PSJUTiBHSVMgV2F0ZXIgRGF0YSBEb3dubG9hZCIgc3R5bGU9IndpZHRoOjEwMCUiPjwvcD4NCg0KQnkgY2xpY2tpbmcgdGhlIGxpbmssIGEgbmV3IHdpbmRvdyB3aWxsIG9wZW4gd2l0aCBhIEdvb2dsZSBEcml2ZSBkb3dubG9hZCBwYWdlLiBPbiB0aGlzIHNjcmVlbiB5b3UgY2FuIGxvY2F0ZSB0aGUgX2ZpbGUgSURfIHdpdGhpbiB0aGUgVVJMLg0KDQo8cCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0gIkltYWdlcy9nb29nbGUtZHJpdmUtbGluay5wbmciIGFsdD0iR29vZ2xlIERyaXZlIERvd25sb2FkIExpbmsiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L3A+DQoNClRoaXMgSUQgd2lsbCBiZSB1c2VkIGluIHRoZSBgZHJpdmVfZG93bmxvYWRzYCBmdW5jdGlvbiB0byBvYnRhaW4gdGhlIGZpbGUuDQoNCmBgYHtyIGdvb2dsZSBkcml2ZSBkb3dubG9hZCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KZHJpdmVfZGVhdXRoKCkNCmRyaXZlX2Rvd25sb2FkKGFzX2lkKCIwQjlVSWRHaUJfTFhPZVZWUU5tOTFiR3B2VVVFIiksIG92ZXJ3cml0ZSA9IFRSVUUpDQpgYGANCg0KT24gdGhlIEdvb2dsZSBDb2xhYm9yYXRvcnkgcGFnZSB5b3Ugd2lsbCBzZWUgYSBmb2xkZXIgYnV0dG9uIDxpbWcgc3JjPSAiSW1hZ2VzL2dvb2dsZS1jb2xhYi1maWxlcy1idXR0b24uanBnIiBhbHQ9Ikdvb2dsZSBDb2xhYiBGaWxlcyBCdXR0b24iIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCI+IG9uIHRoZSBsZWZ0IHRoYXQgb3BlbnMgYSBuZXcgcGFuZSBvbiB0aGUgbGVmdCBvZiB0aGUgc2NyZWVuLiBUaGUgImRpcmVjdG9yeSIgZm9yIHRoaXMgbG9jYXRpb24gaXMgYC9jb250ZW50L2Agd2hpY2ggY2FuIGJlIGRpcmVjdGx5IGFjY2Vzc2VkIHdpdGhpbiBDb2xhYi4gDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxpbWcgc3JjPSAiSW1hZ2VzL2NvbGFiLWZpbGVzLXRhYi5wbmciIGFsdD0iQ29sYWIgRmlsZXMgVGFiIiBzdHlsZT0id2lkdGg6MTAwJSI+PC9wPg0KDQpUaGUgc2NyaXB0IGFib3ZlIGRvd25sb2FkZWQgdGhlICoqdG5fd2JkLnppcCoqIGZpbGUgdGhhdCBpcyBub3cgbG9jYXRlZCBpbiB0aGUgY29udGVudHMgZm9sZGVyLiBZb3UgY2FuIHVzZSB0aGUgYHVuemlwYCBmdW5jdGlvbiB0byBleHRyYWN0IHRoZSBuZWNlc3NhcnkgZGF0YS4NCg0KYGBge3IgdW56aXAgMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KdW56aXAoJ3RuX3diZC56aXAnKQ0KYGBgDQoNCkluIHRoZSBmb2xkZXJzIHBhbmUgeW91IGNhbiBzZWUgdGhyZWUgYWRkaXRpb25hbCBmaWxlcyB3ZXJlIGV4dHJhY3RlZC4gVGhlc2UgYXJlIHdhdGVyc2hlZCBmaWxlcyBhdCB2YXJ5aW5nIGxldmVscyBvZiBkZXRhaWwuIEZvciBoeWRyb2xvZ2ljIHVuaXRzIHRoZSBmaWxlIG9wdGlvbiB3aXRoIHRoZSBsYXJnZXN0IG51bWJlciBvZiBkaWdpdHMgKGUuZy4gOC1kaWdpdCBIdWMgdnMgMTItZGlnaXQgSFVDKSBwcm92aWRlcyB0aGUgbGFyZ2VzdCBzY2FsZSBkYXRhLiBTbyBmb3IgdGhpcyBleGVyY2lzZSB5b3Ugd2lsbCB1bnppcCB0aGUgKip0bl8xMmRpZ19odWMuemlwKiogZGF0YXNldC4gSW4gb3JkZXIgdG8gaGVscCBvcmdhbml6ZSB0aGUgZGF0YSwgeW91IHdpbGwgYWRkIGEgX2V4ZGlyID1fIGNhbGwgdG8gdGhlIHNjcmlwdCB0byBjcmVhdGUgYSBuZXcgZm9sZGVyIGZvciB0aGUgZGF0YSB3aXRoaW4gdGhlIGNvbnRlbnRzIGZvbGRlci4gQmVjYXVzZSB0aGlzIGV4ZXJjaXNlIGlzIHNwZWNpZmljIHRvIENvbGFiIHRoZSBzY3JpcHRzIGJlbG93IHdpbGwgZGlmZmVyIGlmIHlvdSBhcmUgdXNpbmcgZGlmZmVyZW50IElERSBmb3IgUi4NCg0KYGBge3IgdW56aXAgMiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KdW56aXAoJ3RuXzEyZGlnX2h1Yy56aXAnLCBleGRpciA9ICIvY29udGVudC93YXRlcnNoZWRzIikNCmBgYA0KDQpOb3cgeW91IGNhbiBvcGVuIHRoZSB3YXRlcnNoZWRzIGZvbGRlciBhbmQgdmlldyB0aGUgY29udGVudHMuIER1ZSB0byB0aGUgZmlsZSBzdHJ1Y3R1cmUgb2YgdGhlIHppcCBmaWxlLCB0aGUgdW5jb21wcmVzc2VkIGRhdGEgbm93IGNvbnRhaW5zIHRoZSBjaGFyYWN0ZXJzICoqaHlkcm9sb2dpY191bml0c1xcKiogaW4gZnJvbnQgb2YgdGhlIGZpbGUgbmFtZS4gW1Jde3N0eWxlPSJjb2xvcjogIzY0OTVFRCJ9IHdpbGwgbm90IHBlcm1pdCB0aGVzZSBjaGFyYWN0ZXJzIHdpdGhpbiBhIGZpbGUgb3Igb2JqZWN0IHRoZXJlZm9yZSB5b3UgbmVlZCB0byByZW5hbWUgdGhlIGRhdGEgYmVmb3JlIHlvdSBjYW4gY29udGludWUuDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxkaXYgY2xhc3M9Inpvb20iPjxpbWcgc3JjPSAiSW1hZ2VzL2NvbGFiLWZpbGUtbmFtZXMucG5nIiBhbHQ9IkluYWNjZXNzaWJsZSBGaWxlIE5hbWVzIiBzdHlsZT0id2lkdGg6MTAwJSI+PC9kaXY+PC9wPg0KDQpUbyBzdGFydCB0aGlzIHByb2Nlc3MgeW91IHdpbGwgY3JlYXRlIGEgbGlzdCBvZiBmaWxlcyBpbiB0aGUgX3dhdGVyc2hlZF8gZm9sZGVyIHRoYXQgY29udGFpbnMgdGhlICJoeWRyb2xvZ2ljX3VuaXRzIiBwcmVmaXguIFNpbmNlIHdlIG5lZWQgdG8gY29uc2lzdGVudGx5IHJlbW92ZSB0aGUgZmlyc3Qgc2V2ZW50ZWVuIGNoYXJhY3RlcnMsIHlvdSBjYW4gdXNlIHRoZSBgc3ViYCBmdW5jdGlvbiB0byByZW1vdmUgdGhvc2UgY2hhcmFjdGVycy4gQWx0ZXJuYXRpdmVseSBpZiB5b3UganVzdCBuZWVkZWQgdG8gcmVuYW1lIHNvbWUgZmlsZXMgeW91IGNvdWxkIGFkZCBjaGFyYWN0ZXJzIGJldHdlZW4gdGhlIGFwb3N0cm9waGVzLg0KDQpgYGB7ciBsaXN0IGZpbGUgbmFtZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0NCm5hbWVzIDwtIGxpc3QuZmlsZXMocGF0aCA9ICIvY29udGVudC93YXRlcnNoZWRzIiwgcGF0dGVybiA9ICJoeWRyb2xvZ2ljX3VuaXRzIikNCm5ld19uYW1lcyA8LSBzdWIoJy4uLi4uLi4uLi4uLi4uLi4uJywnJyxuYW1lcykNCmBgYA0KDQpCZWNhdXNlIGBmaWxlLnJlbmFtZWAgb3BlcmF0ZXMgYXQgdGhlIHJvb3QgZGlyZWN0b3J5IGxldmVsLCB5b3UgbmVlZCB0byB0ZW1wb3JhcmlseSBkaXJlY3QgdGhlIHdvcmtpbmcgZGlyZWN0b3J5IHRvIHRoZSBsb2NhdGlvbiBvZiB0aGUgaW5hcHByb3ByaWF0ZWx5IG5hbWVkIGZpbGVzLCByZW5hbWUgdGhlbSwgdGhlbiByZXR1cm4gdG8gdGhlIGNvcnJlY3Qgd29ya2luZyBkaXJlY3RvcnkuIEl0IGlzIHBvc3NpYmxlIHRoZXJlIGlzIGEgd2F5IGFyb3VuZCB0aGlzLCB1bmZvcnR1bmF0ZWx5IHZpYSBDb2xhYiBvciBSU3R1ZGlvIEkgZG8gbm90IGtub3cgaG93IHRvIHVzZSBgZmlsZS5uYW1lYCBvdXRzaWRlIG9mIHRoZSBkaXJlY3RvcnkgY29udGFpbmluZyB0aGUgdmFsdWVzLg0KDQpgYGB7ciByZW5hbWUgZmlsZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0NCnNldHdkKCIvY29udGVudC93YXRlcnNoZWRzIikNCmZpbGUucmVuYW1lKG5hbWVzLG5ld19uYW1lcykNCnNldHdkKCIvY29udGVudCIpDQpgYGANCg0KSWYgeW91IG5hdmlnYXRlIGJhY2sgdG8gdGhlIGZpbGVzIHBhbmUgeW91IGNhbiBub3cgc2VlIHRoZSB3YXRlcnNoZWQgZmlsZXMgaGF2ZSBiZWVuIHJlbmFtZWQuIFRvIHJldHVybiB0byB0aGUgY29udGVudCBmb2xkZXIgeW91IGNhbiB1c2UgdGhlIF91cCBkaXJlY3RvcnlfIGJ1dHRvbiA8aW1nIHNyYz0gIkltYWdlcy9jb2xhYi1maWxlcy11cC1idXR0b24uanBnIiBhbHQ9Ikdvb2dsZSBDb2xhYiBVcCBEaXJlY3RvcnkgQnV0dG9uIiB3aWR0aD0iMjAiIGhlaWdodD0iMjAiPi4NCg0KPHAgYWxpZ249ImNlbnRlciI+PGRpdiBjbGFzcz0iem9vbSI+PGltZyBzcmM9ICJJbWFnZXMvY29sYWItbmV3LW5hbWVzLnBuZyIgYWx0PSJSZW5hbWVkIEZpbGUiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L2Rpdj48L3A+DQoNCk5vdyB5b3UgY2FuIHVzZSB0aGUgYHJlYWRPR1JgIGZ1bmN0aW9uIGZyb20gYHJnZW9zYCB0byByYWQgaW4gdGhlIHNoYXBlZmlsZSB0byBhIG5ldyBvYmplY3QuDQoNCmBgYHtyIHJlYWQgaW4gd2F0ZXJzaGVkcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0Kd2F0ZXJzaGVkc19kYXRhIDwtIHJlYWRPR1IoIi9jb250ZW50L3dhdGVyc2hlZHMvd2JkaHUxMl9hX3RuLnNocCIpDQpgYGANCg0KV2l0aCB0aGUgd2F0ZXJzaGVkcyBkYXRhc2V0IGNyZWF0ZWQgeW91IG5lZWQgdG8gYWRkcmVzcyB0aGUgcmVtYWluaW5nIGRhdGFzZXRzLiBVc2luZyBzaW1pbGFyIHN0ZXBzIHRvIHByZXZpb3VzIGV4ZXJjaXNlcyB5b3Ugd2lsbCBub3cgZG93bmxvYWQgYW5kIGNyZWF0ZSBhIGJyb3duZmllbGRzIGRhdGFzZXQuIFlvdSB3aWxsIGFsc28gY3JlYXRlIGEgbmV3IGZvbGRlciBmb3IgdGhpcyBkYXRhIGp1c3QgbGlrZSBpbiB0aGUgd2F0ZXJzaGVkIHNjcmlwdCBhYm92ZS4NCg0KYGBge3IgcmVhZCBpbiBicm93bmZpZWxkcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KZG93bmxvYWQuZmlsZSgnaHR0cHM6Ly9naXRodWIuY29tL2NocmlzbWdlbnRyeS9HSVMxLUV4ZXJjaXNlLTUvcmF3L21haW4vRGF0YS9icm93bmZpZWxkcy56aXAnLCAnYnJvd25maWVsZHMuemlwJykNCnVuemlwKCdicm93bmZpZWxkcy56aXAnLCBleGRpciA9ICIvY29udGVudC9icm93bmZpZWxkcyIpDQpicm93bmZpZWxkc19kYXRhIDwtIHJlYWRPR1IoIi9jb250ZW50L2Jyb3duZmllbGRzL2Jyb3duZmllbGRzLnNocCIpDQpgYGANCg0KVGhlIG5leHQgZGF0YXNldCB0byBpbXBvcnQgd2lsbCBiZSB0aGUgW2RlbW9ncmFwaGljc10oaHR0cHM6Ly9naXRodWIuY29tL2NocmlzbWdlbnRyeS9HSVMxLUV4ZXJjaXNlLTUvYmxvYi9tYWluL0RhdGEvZGVtb2dyYXBoaWNzLmNzdikgZGF0YXNldCBmcm9tIHRoZSBleGVyY2lzZSBHaXRIdWIgcGFnZS4gQmVjYXVzZSB0aGUgZGF0YSBpcyBhIHNpbXBsZSBcKi5jc3YgZmlsZSBpdCBjYW4gZWFzaWx5IGJlIHJlYWQgaW4gd2l0aCB0aGUgYHJlYWQuY3N2YCBmdW5jdGlvbi4NCg0KYGBge3IgcmVhZCBpbiBkZW1vZ3JhcGhpY3MsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0NCmRlbW9ncmFwaGljcyA8LSByZWFkLmNzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2NocmlzbWdlbnRyeS9HSVMxLUV4ZXJjaXNlLTUvbWFpbi9EYXRhL2RlbW9ncmFwaGljcy5jc3YnKQ0KYGBgDQoNClRoZSBmaW5hbCBkYXRhc2V0IHRvIGltcG9ydCBpcyB0aGUgY2Vuc3VzIHRyYWN0IGZvciBNb250Z29tZXJ5IENvdW50eS4gVXNpbmcgdGhlIGB0aWdyaXNgIHBhY2thZ2UgbGlrZSBpbiBbRXhlcmNpc2UgMywgU3RlcCAxXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS0zLyMxMV9TdGVwX09uZTpfVGhlX0RhdGEpIHlvdSBjYW4gdXNlIGB0cmFjdHNgIHRvIG9idGFpbiB0aGUgZGF0YXNldC4NCg0KYGBge3IgcmVhZCBpbiBjZW5zdXMgdHJhY3RzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9DQptb250Y29fdHJhY3RzIDwtIHRyYWN0cygiVE4iLCBjb3VudHkgPSAiTW9udGdvbWVyeSIpDQpgYGANCg0KVGhyZWUgb2YgdGhlc2UgZGF0YXNldHMgKGJyb3duZmllbGRzLCB3YXRlcnNoZWRzLCBhbmQgY2Vuc3VzIHRyYWN0cykgYXJlIGFscmVhZHkgaW4gc3BhdGlhbCBkYXRhIGZvcm1hdHMuIEluIG9yZGVyIHRvIHBlcmZvcm0gZnVydGhlciBhbmFseXNpcyB5b3UgbmVlZCB0byBtYWtlIHN1cmUgdGhleSBoYXZlIHRoZSBzYW1lIGNvb3JkaW5hdGUgcmVmZXJlbmNlIHN5c3RlbSAoY3JzKS4NCg0KYGBge3IgY2hlY2sgY3JzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9DQpjcnMod2F0ZXJzaGVkc19kYXRhKQ0KY3JzKGJyb3duZmllbGRzX2RhdGEpDQpjcnMobW9udGNvX3RyYWN0cykNCmBgYA0KDQpZb3UgY2FuIHNlZSB0aGV5IGFyZSBhbGwgaW4gZGlmZmVyZW50IHByb2plY3Rpb25zLiBUaGVyZWZvcmUgeW91IG5lZWQgdG8gcmVwcm9qZWN0IHRoZW0gdW5kZXIgYSBzaW5nbGUgY3JzLiBGb3IgdGhpcyBleGVyY2lzZSB5b3Ugd2lsbCB1c2UgKipFUFNHOjQzMjYqKiB3aGljaCBpbiBSIGFwcGVhcnMgYXMgXytwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0ICtub19kZWZzXyB3aGVuIHJlZmVyZW5jZWQgaW4gdGhlIHNjcmlwdC4gQmVjYXVzZSB0aGUgYnJvd25maWVsZHMgZGF0YSBpcyBhbHJlYWR5IGluIHRoaXMgY3JzIHlvdSBjYW4gdXNlIGl0IG9yIHRoZSBFUFNHIHRvIGNvcnJlY3QgdGhlIG90aGVyIGRhdGFzZXRzLiBSZW1lbWJlciBmcm9tIF9FeGVyY2lzZSAzXyB0aGF0IGRhdGEgZnJvbSBgdGlncmlzYCBpcyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBzcGF0aWFsIGRhdGEgc3RydWN0dXJlICggX3NmXyB2cy4gX1NwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZV8pIHNvIHRoZSBwcm9jZXNzIHRvIHJlcHJvamVjdCB0aGF0IGRhdGEgd2lsbCB2YXJ5IGZyb20gdGhlIHdhdGVyc2hlZHMgZGF0YXNldC4NCg0KYGBge3IgcmVwcm9qZWN0IGRhdGEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0NCndhdGVyc2hlZHNfZGF0YSA8LSBzcFRyYW5zZm9ybSh3YXRlcnNoZWRzX2RhdGEsIGNycyhicm93bmZpZWxkc19kYXRhKSkNCm1vbnRjb190cmFjdHMgPC0gc3RfdHJhbnNmb3JtKG1vbnRjb190cmFjdHMsIDQzMjYpDQpgYGANCg0KWW91IGNhbiBub3cgY2hlY2sgdGhlIGNycyBpbmZvcm1hdGlvbiBmb3IgZWFjaCBkYXRhc2V0IGFuZCB0aGV5IHNob3VsZCBhbGwgYmUgaW4gRVBTRzo0MzI2IChvciArcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCArbm9fZGVmcykuIFdpdGggdGhlIGRhdGEgY3JlYXRlZCBhbmQgcmVwcm9qZWN0ZWQgdG8gdGhlIHNhbWUgY3JzIHlvdSBjYW4gbW92ZSBvbiB0byB0aGUgYW5hbHlzaXMuDQoNCjxiaWc+PGI+UXVlc3Rpb24gTm8uIDE8L2I+PC9iaWc+PGJyPg0KVXNpbmcgdGhlIGZpbGVzIGJ1dHRvbiBvbiB0aGUgbGVmdCwgZXhhbWluZSB0aGUgZGF0YXNldCBjb250YWluZWQgaW4gdGhlIGJyb3duZmllbGRzLnppcCBmaWxlIGFuZCBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbjoNCjxibG9ja3F1b3RlPg0KV2hhdCBpcyB0aGUgY29tbW9uIG5hbWUgb2YgdGhlIGV4dHJhY3RlZCBmaWxlcz8gSG93IG1hbnkgYXJlIHRoZXJlPyBXaGF0IGFyZSB0aGUgdmFyaW91cyBmaWxlIGV4dGVuc2lvbnM/DQo8L2Jsb2NrcXVvdGU+DQo8c21hbGw+VGhlIGxpYnJhcnkgb2YgQ29uZ3Jlc3MgaGFzIGEgZ3JlYXQgZGVzY3JpcHRpb24gb2YgdGhlIHZhcmlvdXMgZXh0ZW5zaW9ucyBbaGVyZV0oaHR0cHM6Ly93d3cubG9jLmdvdi9wcmVzZXJ2YXRpb24vZGlnaXRhbC9mb3JtYXRzL2ZkZC9mZGQwMDAyODAuc2h0bWwpLjwvc21hbGw+DQoNCjwvZGV0YWlscz4NCg0KIyMgU3RlcCBUd286IFRoZSBBbmFseXNlcw0KDQpUaGUgZGF0YSBjb2xsZWN0ZWQgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24gcmVxdWlyZXMgYWRkaXRpb25hbCBwcm9jZXNzaW5nIHNvIHlvdSBjYW4gcmVkdWNlIHRoZSBkYXRhc2V0IHRvIG9ubHkgdGhlIHBlcnRpbmVudCBpbmZvcm1hdGlvbiBmb3IgdGhlIGFuYWx5c2VzLiBJbiB0aGlzIHN0ZXAgeW91IHdpbGwgdXNlIGFkZGl0aW9uYWwgZ2VvcHJvY2Vzc2luZyB0ZWNobmlxdWVzIGFuZCBkYXRhIG1hbmFnZW1lbnQgdG9vbHMgdG8gbGluayB0d28gZGF0YXNldHMgZm9yIGZ1cnRoZXIgZXhhbWluYXRpb24uDQoNCjxkZXRhaWxzPg0KPHN1bW1hcnk+PGJpZz5WaWV3IERpcmVjdGlvbnMgaW4gPGI+IFtBcmNHSVMgUHJvXXtzdHlsZT0iY29sb3I6I2ZmNDUwMCJ9IDwvYj48L2JpZz48L3N1bW1hcnk+DQoNCldpdGggdGhlIGRhdGEgY29sbGVjdGVkIHlvdSBjYW4gbm93IGFkZCB0aGUgX2Jyb3duZmllbGRzXywgY2Vuc3VzIHRyYWN0cywgX3Rvcm5hZG9fZGF0YV8sIGFuZCBfd2JkaHUxMl9hX3RuXyAod2F0ZXJzaGVkcykgZGF0YSB0byB5b3VyIHByb2plY3QuIEFsdGhvdWdoIHRoZXJlIGFyZSBhIG51bWJlciBvZiB3YXlzIG9mIGlzb2xhdGluZyBkYXRhIHRvIG1ha2UgZGVyaXZlZCBkYXRhc2V0cyAoZS5nLiBTZWxlY3QgPiBMYXNzbyBpbiBbRXhlcmNpc2UgNCwgU3RlcCAxXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS00LyMxMV9TdGVwX09uZTpfVGhlX0RhdGEpKSwgaW4gdGhpcyBleGVyY2lzZSB5b3Ugd2lsbCB1c2UgYW5vdGhlciB0b29sIGZyb20gdGhlICoqR2VvcHJvY2Vzc2luZyoqIFRvb2xib3ggdG8gY29tcGxldGUgdGhpcyB0YXNrLiBPbiB0aGUgX1ZpZXcgVGFiXyBjbGljayBvbiB0aGUgR2VvcHJvY2Vzc2luZyBUb29sYm94IGJ1dHRvbiA8aW1nIHNyYz0gIkltYWdlcy9nZW9wcm9jZXNzaW5nLWJ1dHRvbi5qcGciIGFsdD0iR2VvcHJvY2Vzc2luZyBCdXR0b24iIHdpZHRoID0gIjIwIiBoZWlnaHQgPSAiMjAiPiB0byBvcGVuIHRoZSBHZW9wcm9jZXNzaW5nIHBhbmUgb24gdGhlIHJpZ2h0IHNpZGUgb2YgdGhlIHNjcmVlbi4gQnkgbmF2aWdhdGluZyB0aHJvdWdoIHRoZSB0b29scyBtZW51cyB5b3Ugd2lsbCBmaW5kICoqU2VsZWN0KiogdW5kZXIgX0FuYWx5c2lzIFRvb2xzID4gRXh0cmFjdF8uIA0KV2l0aCB0aGlzIHRvb2wgeW91IHdpbGwgd3JpdGUgYSBzaW1wbGUgZXhwcmVzc2lvbiB0byAic2VsZWN0IiBhIHNtYWxsIHBvcnRpb24gb2YgdGhlIGRhdGEgeW91IG5lZWQgZm9yIGZ1cnRoZXIgYW5hbHlzaXMuIFRvIGRvIHRoaXMsIGRvdWJsZS1jbGljayB0aGUgX1NlbGVjdF8gdG9vbCBhbmQgaW4gdGhlIHJlc3VsdGluZyBwYW5lIGlucHV0IHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyczoNCg0KLSBJbnB1dCBGZWF0dXJlcyA9IHRvcm5hZG9fZGF0YVwqDQotIE91dHB1dCBGZWF0dXJlIENsYXNzID0gSGVyZSB5b3Ugd2lsbCBpbnNlcnQgdGhlIGZpbGUgbmFtZSB5b3Ugd2FudCB0byB1c2UuIENsaWNrIG9uIHRoZSBmb2xkZXIgaWNvbiB0byB0aGUgcmlnaHQgb2YgdGhlIGZpZWxkIGFuZCBpbiB0aGUgbmV3IHdpbmRvdyBzYXZlIHRoZSBmaWxlIGFzIF9tb250Z29tZXJ5X2NvdW50eS5zaHBfIGluIHlvdXIgcHJvamVjdCBmb2xkZXIuDQotIEV4cHJlc3Npb24gPSBDbGljayB0aGUgZHJvcC1kb3duIGJ1dHRvbiBmb3IgdGhlIG5ldyBleHByZXNzaW9uIDxpbWcgc3JjPSAiSW1hZ2VzL25ldy1leHByZXNzaW9uLWJ1dHRvbi5qcGciIGFsdD0iRXhwcmVzc2lvbiBCdXR0b24iIHdpZHRoID0gIjg3IiBoZWlnaHQgPSAiMjAiPiBidXR0b24gYW5kIHVzZSB0aGUgZHJvcC1kb3duIGJveGVzIHRvIHByb3ZpZGUgdGhlIGZvbGxvd2luZyBpbmZvcm1hdGlvbjogDQogIC0gV2hlcmUgX05BTUVfICZuYnNwOyBfaXMgZXF1YWwgdG9fICZuYnNwOyBfTW9udGdvbWVyeV8NCiAgLSBDbGljayBSdW4NCg0KPHAgYWxpZ249ImNlbnRlciI+PGRpdiBjbGFzcz0iem9vbSI+PGltZyBzcmM9ICJJbWFnZXMvc2VsZWN0LWdlb3Byb2Nlc3NpbmcucG5nIiBhbHQ9IlNlbGVjdCBHZW9wcm9jZXNzaW5nIFRvb2wiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L2Rpdj48L3A+DQpcKlRoZSB0b3JuYWRvIGRhdGFzZXQgaXMgb25seSBiZWluZyB1c2VkIHRvIG9idGFpbiBhIHBvbHlnb24gZm9yIE1vbnRnb21lcnkgQ291bnR5IGZvciB0aGUgY2xpcCBwcm9jZXNzIGluIHRoZSBuZXh0IHN0ZXAuIA0KDQpUaGlzIHdpbGwgYWRkIHRoZSBuZXcgKiptb250Z29tZXJ5X2NvdW50eSoqIHNoYXBlZmlsZSB0byB5b3VyIGNvbnRlbnRzLiBZb3UgY2FuIG5vdyByZW1vdmUgdGhlIHRvcm5hZG8gZGF0YXNldCBiZWNhdXNlIGl0IHdpbGwgbm8gbG9uZ2VyIGJlIG5lZWRlZC4gV2l0aCB0aGUgcG9seWdvbiBvZiBNb250Z29tZXJ5IENvdW50eSBhdmFpbGFibGUgeW91IGNhbiBub3cgdXNlIHRoZSAqKkNsaXAqKiB0b29sIGxpa2UgaW4gW0V4ZXJjaXNlIDQsIFN0ZXAgT25lXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS00LyMxMV9TdGVwX09uZTpfVGhlX0RhdGEpIHRvIGNsaXAgdGhlIF9icm93bmZpZWxkc18gYW5kIF93YXRlcnNoZWRzXyBkYXRhc2V0cyB0byByZWR1Y2UgdGhlbSB0byBvbmx5IHRob3NlIHdpdGhpbiBNb250Z29tZXJ5IENvdW50eS4gSWYgeW91IHJlY2VpdmUgYSAiRGF0dW0gY29uZmxpY3QiIHdhcm5pbmcsIGZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBleGVyY2lzZSwgeW91IGNhbiBpZ25vcmUgaXQgYW4gY29udGludWUgd2l0aCB0aGUgY2xpcC4gUmVjYWxsIHRoYXQgdGhlIF9JbnB1dCBGZWF0dXJlc18gaXMgdGhlIGRhdGEgeW91IHdhbnQgdG8gcmVkdWNlLCB0aGUgX0NsaXAgRmVhdHVyZV8gaXMgdGhlIGRhdGEgeW91IHdhbnQgaXQgdG8gdGFrZSB0aGUgc2hhcGUgb2YsIGFuZCBfT3V0cHV0IEZlYXR1cmUgQ2xhc3NfIGlzIHdoYXQgeW91IGFyZSBuYW1pbmcgdGhlIG5ldyBmaWxlLiBSZWZlciBiYWNrIHRvIFtFeGVyY2lzZSA0LCBTdGVwIE9uZV0oaHR0cHM6Ly9jaHJpc21nZW50cnkuZ2l0aHViLmlvL0dJUzEtRXhlcmNpc2UtNC8jMTFfU3RlcF9PbmU6X1RoZV9EYXRhKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCBDbGlwLg0KDQo8cCBhbGlnbj0iY2VudGVyIj48ZGl2IGNsYXNzPSJ6b29tIj48aW1nIHNyYz0gIkltYWdlcy9jbGlwcGVkLWRhdGEucG5nIiBhbHQ9IlNlbGVjdCBDbGlwcGVkIERhdGFzZXRzIiBzdHlsZT0id2lkdGg6MTAwJSI+PC9kaXY+PC9wPg0KDQpXaXRoIHRoZSBuZXcgY2xpcHBlZCBkYXRhc2V0cyB5b3UgY2FuIHJlbW92ZSBvciBqdXN0IHVuY2hlY2sgKGluIGNhc2UgeW91IHdhbnQgdG8gdXNlIHRoZW0gaW4geW91ciBmaW5hbCBtYXApIHRoZSBmdWxsIF9icm93bmZpZWxkc18gYW5kIF93YXRlcnNoZWRzXyBkYXRhc2V0cyB0byByZWR1Y2UgY2x1dHRlci4gWW91IGNhbiBhbHNvIG5vdyB6b29tIGluIGNsb3NlciB0byB2aWV3IG9ubHkgTW9udGdvbWVyeSBDb3VudHkuDQoNCkluIHRoZSBmaW5hbCBzdGVwIHRvIHByZXBhcmUgdGhlIGRhdGEsIHlvdSBhcmUgZ29pbmcgdG8gY29ubmVjdCBhIG5vbi1zcGF0aWFsIGRhdGEgdG8gdGhlIGNlbnN1cyB0cmFjdCBkYXRhc2V0LiBJbiBbU3RlcCBPbmVdKGh0dHBzOi8vY2hyaXNtZ2VudHJ5LmdpdGh1Yi5pby9HSVMxLUV4ZXJjaXNlLTUvIzExX1N0ZXBfT25lOl9UaGVfRGF0YSkgeW91IGRvd25sb2FkZWQgYSBmaWxlIHRpdGxlZCAqKmRlbW9ncmFwaGljcy5jc3YqKi4gVGhpcyBmaWxlIGNvbnRhaW5zIGNvbW1hLXNlcGFyYXRlZCB2YWx1ZXMgZGV0YWlsaW5nIGFkZGl0aW9uYWwgZGVtb2dyYXBoaWMgZGF0YSB0aGF0IHlvdSBuZWVkIHRvIGFwcGVuZCB0byB0aGUgY2Vuc3VzIHRyYWN0IGRhdGEuIEFsdGhvdWdoIHRoZSBwcm9jZXNzIGlzIHJlbGF0aXZlbHkgc3RyYWlnaHQtZm9yd2FyZCwgdGhlcmUgYXJlIGEgbnVtYmVyIG9mIHN0ZXBzIHRoYXQgbmVlZCB0byBiZSB0YWtlbiBpbiBvcmRlciB0byBqb2luIHRoZSBkYXRhLg0KDQpGaXJzdCwgaWYgeW91IGhhdmVuJ3QgYWxyZWFkeSwgYWRkIHRoZSBfZGVtb2dyYXBoaWNzLmNzdl8gZmlsZSB0byB5b3VyIHRhYmxlIG9mIGNvbnRlbnRzLiBUaGlzIGNhbiBiZSBkb25lIGZyb20gdGhlIENhdGFsb2cgUGFuZSBvciB3aXRoIHRoZSAiQWRkIERhdGEiIGJ1dHRvbiA8aW1nIHNyYz0gIkltYWdlcy9hcmNnaXMtYWRkLWRhdGEtYnV0dG9uLnBuZyIgYWx0PSJBZGQgRGF0YSBCdXR0b24iIHdpZHRoID0gIjE2IiBoZWlnaHQgPSAiMjAiPiBsaWtlIGluIHByZXZpb3VzIGV4ZXJjaXNlcy4gQmVjYXVzZSBbQXJjR0lTIFByb117c3R5bGU9ImNvbG9yOiNmZjQ1MDAifSB0cmVhdHMgXCouY3N2IGZpbGVzIGFzICJyZWFkIG9ubHkiIHlvdSBuZWVkIHRvIGNvbnZlcnQgaXQgdG8gYSB0YWJsZSB0aGF0IGNhbiBiZSBlZGl0ZWQgaW4gdGhlIHNvZnR3YXJlLiBOb3csIHJpZ2h0LWNsaWNrIG9uIHRoZSBfZGVtb2dyYXBoaWNzLmNzdl8gc3RhbmRhbG9uZSB0YWJsZSBhbmQgZ28gdG8gKipEYXRhID4gRXhwb3J0IFRhYmxlKiouIEluIHRoZSByZXN1bHRpbmcgd2luZG93IGNob29zZSB0aGUgZm9sbG93aW5nIG9wdGlvbnM6DQoNCi0gSW5wdXQgUm93cyA9IGRlbW9ncmFwaGljcy5jc3YNCi0gT3V0cHV0IExvY2F0aW9uID0gU2ltaWxhciB0byBiZWZvcmUsIG5hdmlnYXRlIG9ubHkgdG8geW91ciBwcm9qZWN0IGZvbGRlciBhbmQgY2xpY2sgb25jZSB0byBzZWxlY3QuIEluIHRoZSBzdGVwIHlvdSBhcmUgc2ltcGx5IGRlc2lnbmF0aW5nIHRoZSBmb2xkZXIgdGhlIGZpbGUgaXMgdG8gYmUgc2F2ZWQuDQotIE91dHB1dCBOYW1lID0gR2l2ZSB0aGUgZmlsZSBhIG5ldyBuYW1lIHN1Y2ggYXMgZGVtb190YWJsZS5kYmYNCg0KQmVmb3JlIGNsaWNraW5nIE9LLCB5b3UgbmVlZCB0byBleHBhbmQgdGhlICoqRmllbGRzKiogc2VjdGlvbiBvZiB0aGUgd2luZG93IGFuZCBjbGljayBvbiBfVHJhY3RfIGluIHRoZSBPdXRwdXQgRmllbGRzIGNvbHVtbi4gVGhlbiBjbGljayBvbiB0aGUgX1Byb3BlcnRpZXNfIFRhYiBhbmQgY2hhbmdlIHRoZSAqKlR5cGUqKiBmaWVsZCB0byBfVGV4dF8uIFRoZW4gY2xpY2sgT0suIElmIHlvdSBjb250aW51ZWQgd2l0aG91dCBjaGFuZ2luZyB0aGUgZmllbGQgdHlwZSwgdGhlIHZhcmlhYmxlIHdvdWxkIG1vc3QgbGlrZWx5IGJlIHRyZWF0ZWQgYXMgYSBudW1lcmljYWwgdmFsdWUuIElmIHlvdSBvcGVuIHRoZSBhdHRyaWJ1dGUgdGFibGUgZm9yIGFueSBkYXRhc2V0IGFuZCBtb3VzZS1vdmVyIHRoZSB2YXJpYWJsZSBjb2x1bW4gd2l0aG91dCBjbGlja2luZyBhIHBvcC11cCB3aW5kb3cgd2lsbCBhcHBlYXIgZGV0YWlsaW5nIHRoZSBfVHlwZV8gYW5kIG90aGVyIHBhcmFtZXRlcnMgb2YgdGhlIHZhcmlhYmxlLiBJbiB0aGUgY2Vuc3VzIGRhdGFzZXQgZnJvbSB0aGUgcHJldmlvdXMgZXhlcmNpc2UsIHRoZSBfTkFNRV8gdmFyaWFibGUgaXMgVHlwZTogVGV4dCAoNykuIFRoZSBzZXZlbiBpbiBwYXJlbnRoZXNpcyBtZWFucyB0aGUgbWF4IG51bWJlciBvZiBhdmFpbGFibGUgY2hhcmFjdGVycyBpcyBzZXZlbi4gU28gYmVmb3JlIHlvdSBleHBvcnQgYSB0YWJsZSBpdCBpcyBnb29kIHByYWN0aWNlIHRvIG1ha2Ugc3VyZSB0aGUgdmFyaWFibGVzIG1hdGNoIHRoZSB2YXJpYWJsZXMgeW91IGludGVuZCB0byBqb2luIG9yIHRoYXQgdGhlIHZhcmlhYmxlcyB3aWxsIGJlIHRyZWF0ZWQgaW4gYSBtYW5uZXIgbmVjZXNzYXJ5IGZvciBhZGRpdGlvbmFsIGFuYWx5c2VzLiANCg0KPHAgYWxpZ249ImNlbnRlciI+PGltZyBzcmM9ICJJbWFnZXMvYXJjZ2lzLXRhYmxlLWV4cG9ydC5wbmciIGFsdD0iRXhwb3J0IENTViB0byBEQkYiIHN0eWxlPSJ3aWR0aDo5MCUiPjwvcD4NCg0KVGhlIG5ldyBzdGFuZGFsb25lIHRhYmxlIHNob3VsZCBoYXZlIGJlZW4gYWRkZWQgdG8gdGhlIFRhYmxlIG9mIENvbnRlbnRzLiBJZiBub3QgeW91IHNob3VsZCBhZGQgaXQgbm93OyB0aGUgY3N2IHRhYmxlIGNhbiBiZSByZW1vdmVkLiBOb3cgeW91IGNhbiBjb25uZWN0IHRoZSBuZXcgdGFibGUgdG8gdGhlIGNlbnN1cyB0cmFjdCBkYXRhc2V0LiBCZWdpbiBieSByaWdodC1jbGlja2luZyBvbiB0aGUgY2Vuc3VzIGRhdGEgYW5kIHNlbGVjdGluZyAqKkpvaW5zIGFuZCBSZWxhdGVzID4gQWRkIEpvaW4qKi4gSW4gdGhlIG5ldyBfQWRkIEpvaW5fIHdpbmRvdyBzZWxlY3QgdGhlIGZvbGxvd2luZyBvcHRpb25zICh5b3VyIGZpbGUgbmFtZXMgbWF5IHZhcnkpOg0KDQotIElucHV0IFRhYmxlID0gbW9udGNvX3RyYWN0cywgb3Igd2hhdGV2ZXIgeW91IG5hbWVkIHRoZSBjZW5zdXMgdHJhY3QgaW5mb3JtYXRpb24NCi0gSW5wdXQgSm9pbiBGaWVsZCA9IE5BTUUNCi0gSm9pbiBUYWJsZSA9IGRlbW9fdGFibGUsIG9yIHdoYXRldmVyIHlvdSBuYW1lZCB0aGUgbmV3IGRlbW9ncmFwaGljcyBkYXRhDQotIEpvaW4gVGFibGUgRmllbGQgPSBUcmFjdA0KDQpGb3IgdGhpcyBleGVyY2lzZSBrZWVwIHRoZSAiS2VlcCBBbGwgVGFyZ2V0IEZlYXR1cmVzIiBidXR0b24gY2hlY2tlZCBhbmQgaWYgeW91IHJlY2VpdmUgYW4gd2FybmluZyBhYm91dCBhbiBpbmRleGluZyBlcnJvciB3aXRoIHRoZSBjZW5zdXMgZGF0YSB5b3UgY2FuIGlnbm9yZSBpdCBmb3IgdGhpcyBleGVyY2lzZS4gVGhlbiBjbGljayB0aGUgX1ZhbGlkYXRlIEpvaW5fIGJ1dHRvbi4gVGhpcyB3aWxsIHBvcC11cCBhbiBuZXcgd2luZG93IHRoYXQgd2lsbCBkZXNjcmliZSB0aGUgcHJvY2VzcyBvZiBjaGVja2luZyB0aGUgdHdvIGRhdGFzZXRzIHRvIHNlZSBpZiB0aGV5IGNhbiBiZSBqb2luZWQuIEF0IHRoZSBib3R0b20gb2YgdGhlIGRpYWxvZyB5b3Ugc2hvdWxkIHNlZSBhIGxpbmUgdGhhdCBzYXlzIHRoZXJlIHdlcmUgMzkgam9pbnMuIENsb3NlIHRoYXQgbWVzc2FnZSBhbmQgY2xpY2sgT0sgdG8gcnVuIHRoZSBqb2luLg0KDQo8cCBhbGlnbj0iY2VudGVyIj48ZGl2IGNsYXNzPSJ6b29tIj48aW1nIHNyYz0gIkltYWdlcy9hcmNnaXMtam9pbi5wbmciIGFsdD0iSm9pbiBEYXRhc2V0cyIgc3R5bGU9IndpZHRoOjEwMCUiPjwvZGl2PjwvcD4NCg0KRmluYWxseSwgb3BlbiB0aGUgYXR0cmlidXRlIHRhYmxlIGZvciB0aGUgY2Vuc3VzIHRyYWN0cyBhbmQgc2Nyb2xsIHRvIHRoZSBmYXIgcmlnaHQgb2YgdGhlIHRhYmxlLiBJZiB0aGUgam9pbiB3b3JrZWQgcHJvcGVybHkgeW91IHNob3VsZCBzZWUgYSBudW1iZXIgb2YgYWRkaXRpb25hbCBmaWVsZHMgYWRkZWQgdG8gdGhlIHRhYmxlLg0KDQo8cCBhbGlnbj0iY2VudGVyIj48ZGl2IGNsYXNzPSJ6b29tIj48aW1nIHNyYz0gIkltYWdlcy9hcmNnaXMtam9pbmVkLXRhYmxlLnBuZyIgYWx0PSJKb2luIERhdGFzZXRzLCBBdHRyaWJ1dGUgVGFibGUiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L2Rpdj48L3A+DQoNClRoaXMgd2lsbCBwcm92aWRlIGFsbCBvZiB0aGUgZGF0YSBhbmQgaW5mb3JtYXRpb24geW91IG5lZWQgdG8gdmlzdWFsaXplIHRoZSBkYXRhIGFuZCBtYWtlIGNvbXBhcmlzb25zIG9mIHRoZSB3YXRlcnNoZWRzLg0KDQo8YmlnPjxiPlF1ZXN0aW9uIE5vLiAyPC9iPjwvYmlnPg0KPGJsb2NrcXVvdGU+DQpIb3cgbWFueSB3YXRlcnNoZWRzIGNvdmVyIE1vbnRnb21lcnkgQ291bnR5PyBBbHRob3VnaCB0aGV5IGhhdmUgYmVlbiBjbGlwcGVkIGZyb20gdGhlaXIgb3JpZ2luYWwgZ2VvbWV0cnksIHdoaWNoIHdhdGVyc2hlZCBpcyB0aGUgbGFyZ2VzdD8gV2hpY2ggaXMgdGhlIHNtYWxsZXN0Pw0KPC9ibG9ja3F1b3RlPg0KDQo8L2RldGFpbHM+DQo8aHI+PC9ocj4NCg0KPGRldGFpbHM+DQo8c3VtbWFyeT48YmlnPlZpZXcgRGlyZWN0aW9ucyBpbiA8Yj4gW1FHSVNde3N0eWxlPSJjb2xvcjojMDA2NDAwIn0gPC9iPjwvYmlnPjwvc3VtbWFyeT4NCg0KV2l0aCB0aGUgZGF0YSBjb2xsZWN0ZWQgeW91IGNhbiBub3cgYWRkIHRoZSBfYnJvd25maWVsZHNfLCBjZW5zdXMgdHJhY3RzLCBfdG9ybmFkb19kYXRhXywgYW5kIF93YmRodTEyX2FfdG5fICh3YXRlcnNoZWRzKSBkYXRhIHRvIHlvdXIgcHJvamVjdC4gQWx0aG91Z2ggdGhlcmUgYXJlIGEgbnVtYmVyIG9mIHdheXMgb2YgaXNvbGF0aW5nIGRhdGEgdG8gbWFrZSBkZXJpdmVkIGRhdGFzZXRzIChlLmcuIFNlbGVjdCBGZWF0dXJlcyA+IFNlbGVjdCBGZWF0dXJlcyBieSBGcmVlaGFuZCBpbiBbRXhlcmNpc2UgNCwgU3RlcCAxXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS00LyMxMV9TdGVwX09uZTpfVGhlX0RhdGEpKSwgaW4gdGhpcyBleGVyY2lzZSB5b3Ugd2lsbCB1c2UgYW5vdGhlciB0b29sIGZyb20gKipWZWN0b3IgU2VsZWN0aW9uKiogaW4gdGhlIF9Qcm9jZXNzaW5nIFRvb2xib3hfIHRvIGNvbXBsZXRlIHRoaXMgdGFzay4NCg0KPHAgYWxpZ249ImNlbnRlciI+PGRpdiBjbGFzcz0iem9vbSI+PGltZyBzcmM9ICJJbWFnZXMvcWdpcy1leDUtZGF0YS5wbmciIGFsdD0iVmVjdG9yIFNlbGVjdGlvbiIgc3R5bGU9IndpZHRoOjEwMCUiPjwvZGl2PjwvcD4NCg0KV2l0aCB0aGlzIHRvb2wgeW91IHdpbGwgc2VsZWN0IG9ubHkgYSBzbWFsbCBwb3J0aW9uIG9mIHRoZSBkYXRhIHlvdSBuZWVkIGZvciBmdXJ0aGVyIGFuYWx5c2lzLiBUbyBkbyB0aGlzLCBkb3VibGUtY2xpY2sgdGhlICJTZWxlY3QiRXh0cmFjdCBieSBBdHRyaWJ1dGUiIHRvb2wgYW5kIGluIHRoZSByZXN1bHRpbmcgd2luZG93IGlucHV0IHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyAoZmlsZSBuYW1lcyBtYXkgdmFyeSk6DQoNCi0gSW5wdXQgbGF5ZXIgPSB0b3JuYWRvX2RhdGENCi0gU2VsZWN0aW9uIGF0dHJpYnV0ZSA9IE5BTUUNCi0gT3BlcmF0b3IgPSA9IChlcXVhbHMgc2lnbikNCi0gVmFsdWUgPSBNb250Z29tZXJ5DQoNClJlbWVtYmVyIHRoYXQgaW4gW1FHSVNde3N0eWxlPSJjb2xvcjojMDA2NDAwIn0geW91IGhhdmUgdGhlIGFiaWxpdHkgdG8gZWl0aGVyIGNyZWF0ZSBwZXJtYW5lbnQgZmlsZXMgb3IgdGVtcG9yYXJ5IGxheWVycy4gQmVjYXVzZSB5b3Ugd2lsbCBvbmx5IGJlIHVzaW5nIHRoZSBNb250Z29tZXJ5IENvdW50eSBkYXRhc2V0IHRvIGNsaXAgZmlsZXMgbGF0ZXIgb24sIHlvdSBjYW4gZGVjaWRlIHdoZXRoZXIgdG8gdXNlIHRoZSBicm93c2UgYnV0dG9uIDxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtZmlsZS1sb2NhdGlvbi1idXR0b24uanBnIiBhbHQ9IkJyb3dzZSBMb2NhdGlvbiBCdXR0b24iIHdpZHRoID0gIjIwIiBoZWlnaHQgPSAiMjAiPiB0byBzYXZlIHRoZSBmaWxlIGZvciBmdXR1cmUgdXNlIG9yIGp1c3QgY3JlYXRlIGEgdGVtcG9yYXJ5IGZpbGUuDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtZXh0cmFjdC1ieS1hdHRyaWJ1dGUucG5nIiBhbHQ9IlNlbGVjdCBieSBBdHRyaWJ1dGUiIHN0eWxlPSJ3aWR0aDo4NSUiPjwvcD4NCg0KVGhpcyB3aWxsIGFkZCB0aGUgbmV3ICoqbW9udGdvbWVyeV9jb3VudHkqKiB0ZW1wb3JhcnkgZmlsZSAob3Igc2hhcGVmaWxlIGlmIHNhdmVkKSB0byB5b3VyIGxheWVycy4gWW91IGNhbiBub3cgcmVtb3ZlIHRoZSB0b3JuYWRvIGRhdGFzZXQgYmVjYXVzZSBpdCB3aWxsIG5vIGxvbmdlciBiZSBuZWVkZWQuIFlvdSBtYXkgYWxzbyBjb25zaWRlciByZW5hbWluZyBpdCBpZiBuZWNlc3NhcnkuIFdpdGggdGhlIHBvbHlnb24gb2YgTW9udGdvbWVyeSBDb3VudHkgYXZhaWxhYmxlIHlvdSBjYW4gbm93IHVzZSB0aGUgKipDbGlwKiogdG9vbCBsaWtlIGluIFtFeGVyY2lzZSA0LCBTdGVwIE9uZV0oaHR0cHM6Ly9jaHJpc21nZW50cnkuZ2l0aHViLmlvL0dJUzEtRXhlcmNpc2UtNC8jMTFfU3RlcF9PbmU6X1RoZV9EYXRhKSB0byBjbGlwIHRoZSBfYnJvd25maWVsZHNfIGFuZCBfd2F0ZXJzaGVkc18gZGF0YXNldHMgdG8gcmVkdWNlIHRoZW0gdG8gb25seSB0aG9zZSB3aXRoaW4gTW9udGdvbWVyeSBDb3VudHkuIFJlY2FsbCB0aGF0IHRoZSBfSW5wdXQgbGF5ZXJfIGlzIHRoZSBkYXRhIHlvdSB3YW50IHRvIHJlZHVjZSAoZS5nLiBicm93bmZpZWxkcyBvciB3YXRlcnNoZWRzKSwgdGhlIF9PdmVybGF5IGxheWVyXyBpcyB0aGUgZGF0YSB5b3Ugd2FudCBpdCB0byB0YWtlIHRoZSBzaGFwZSBvZi4gUmVmZXIgYmFjayB0byBbRXhlcmNpc2UgNCwgU3RlcCBPbmVdKGh0dHBzOi8vY2hyaXNtZ2VudHJ5LmdpdGh1Yi5pby9HSVMxLUV4ZXJjaXNlLTQvIzExX1N0ZXBfT25lOl9UaGVfRGF0YSkgZm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgQ2xpcC4gWW91IHNob3VsZCBnbyBhaGVhZCBhbmQgdXNlIHRoZSBicm93c2UgYnV0dG9uIDxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtZmlsZS1sb2NhdGlvbi1idXR0b24uanBnIiBhbHQ9IkJyb3dzZSBMb2NhdGlvbiBCdXR0b24iIHdpZHRoID0gIjIwIiBoZWlnaHQgPSAiMjAiPiB0byBzYXZlIHRoZXNlIGFzIHBlcm1hbmVudCBmaWxlcy4gQmUgc3VyZSB0byB1c2UgYSBuYW1pbmcgY29udmVudGlvbiB0aGF0IHdpbGwgYWxsb3cgeW91IHRvIHJlY2FsIHdoYXQgdGhlIGZpbGVzIGFyZSBsYXRlciBvbiAoZS5nLiBtb250Y29fYnJvd25maWVsZHMpLg0KDQpXaXRoIHRoZSBuZXcgY2xpcHBlZCBkYXRhc2V0cyB5b3UgY2FuIHJlbW92ZSBvciBqdXN0IHVuY2hlY2sgKGluIGNhc2UgeW91IHdhbnQgdG8gdXNlIHRoZW0gaW4geW91ciBmaW5hbCBtYXApIHRoZSBmdWxsIF9icm93bmZpZWxkc18gYW5kIF93YXRlcnNoZWRzXyBkYXRhc2V0cyB0byByZWR1Y2UgY2x1dHRlci4gWW91IGNhbiBhbHNvIG5vdyB6b29tIGluIGNsb3NlciB0byB2aWV3IG9ubHkgTW9udGdvbWVyeSBDb3VudHkuDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxkaXYgY2xhc3M9Inpvb20iPjxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtbW9udGNvLWRhdGEucG5nIiBhbHQ9Ik1vbnRnb21lcnkgQ291bnR5IERhdGFzZXRzIiBzdHlsZT0id2lkdGg6MTAwJSI+PC9kaXY+PC9wPg0KDQpJbiB0aGUgZmluYWwgc3RlcCB0byBwcmVwYXJlIHRoZSBkYXRhLCB5b3UgYXJlIGdvaW5nIHRvIGNvbm5lY3QgYSBub24tc3BhdGlhbCBkYXRhIHRvIHRoZSBjZW5zdXMgdHJhY3QgZGF0YXNldC4gSW4gW1N0ZXAgT25lXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS01LyMxMV9TdGVwX09uZTpfVGhlX0RhdGEpIHlvdSBkb3dubG9hZGVkIGEgZmlsZSB0aXRsZWQgKipkZW1vZ3JhcGhpY3MuY3N2KiouIFRoaXMgZmlsZSBjb250YWlucyBjb21tYS1zZXBhcmF0ZWQgdmFsdWVzIGRldGFpbGluZyBhZGRpdGlvbmFsIGRlbW9ncmFwaGljIGRhdGEgdGhhdCB5b3UgbmVlZCB0byBhcHBlbmQgdG8gdGhlIGNlbnN1cyB0cmFjdCBkYXRhLiBBbHRob3VnaCB0aGUgcHJvY2VzcyBpcyByZWxhdGl2ZWx5IHN0cmFpZ2h0LWZvcndhcmQsIHRoZXJlIGFyZSBhIG51bWJlciBvZiBzdGVwcyB0aGF0IG5lZWQgdG8gYmUgdGFrZW4gaW4gb3JkZXIgdG8gam9pbiB0aGUgZGF0YS4NCg0KRmlyc3QsIHlvdSB3aWxsIGFkZCB0aGUgKipkZW1vZ3JhcGhpY3MuY3N2KiogdXNpbmcgX0xheWVyID4gQWRkIExheWVyID4gQWRkIERlbGltaXRlZCBUZXh0IExheWVyXyBmcm9tIHRoZSBtZW51IGJhciwgYnkgY2xpY2tpbmcgdGhlICJBZGQgRGVsaW1pdGVkIExheWVyIiBidXR0b24gPGltZyBzcmM9ICJJbWFnZXMvcWdpcy1hZGQtY3N2LWJ1dHRvbi5qcGciIGFsdD0iQWRkIERlbGltaXRlZCBMYXllciIgd2lkdGggPSAiMjAiIGhlaWdodCA9ICIyMCI+LCBvciBieSB1c2luZyB0aGUgc2hvcnRjdXQga2V5cyBDUlRMK1NoaWZ0K1QvQ01EK1NoaWZ0K1QuDQoNCkluIHRoZSByZXN1bHRpbmcgd2luZG93LCB1c2UgdGhlIGJyb3dzZSBidXR0b24gdG8gZmluZCB0aGUgKipkZW1vZ3JhcGhpY3MuY3N2KiogZGF0YSBpbiB5b3VyIHByb2plY3QgZm9sZGVyLiBCZSBzdXJlIHRoYXQgIk5vIGdlb21ldHJ5IChhdHRyaWJ1dGUgb25seSB0YWJsZSkiIGlzIHNlbGVjdGVkIGFuZCB0aGUgdGhlIHJlc3Qgb2YgdGhlIGluZm9ybWF0aW9uIGFzIHRoZSBkZWZhdWx0LiBDbGljayBBZGQuDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxkaXYgY2xhc3M9Inpvb20iPjxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtZGVsaW1pdGVkLWRhdGEucG5nIiBhbHQ9IlRleHQgRGVsaW1pdGVkIERpYWxvZyIgc3R5bGU9IndpZHRoOjEwMCUiPjwvZGl2PjwvcD4NCg0KVGhlIF9kZW1vZ3JhcGhpY3NfIHRhYmxlIHNob3VsZCBub3cgYmUgYWRkZWQgdG8geW91ciBsYXllcnMuIFRvIGNvbm5lY3QgaXQgdG8gdGhlIHBvcHVsYXRpb24gaW5mb3JtYXRpb24sIHJpZ2h0L0NSVEwgY2xpY2sgb24gdGhlIGNlbnN1cyB0cmFjdCBkYXRhIGFuZCBzZWxlY3QgInByb3BlcnRpZXMiLiBJbiB0aGUgUHJvcGVydGllcyBNZW51LCBzZWxlY3QgdGhlIF9Kb2luc18gPGltZyBzcmM9ICJJbWFnZXMvcWdpcy1qb2lucy5qcGciIGFsdD0iSm9pbnMgVGFiIiB3aWR0aCA9ICI0MCIgaGVpZ2h0ID0gIjIwIj4gdGFiIGZyb20gdGhlIGxlZnQgc2lkZSBtZW51LiBBdCB0aGUgYm90dG9tIG9mIHRoZSBzY3JlZW4gY2xpY2sgdGhlIHBsdXMgKCoqKyoqKSBzeW1ib2wgdG8gYWRkIGEgam9pbi4gSW4gdGhlIG5ldyB3aW5kb3cgc2VsZWN0IHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyczoNCg0KLSBKb2luIGxheWVyID0gZGVtb2dyYXBoaWNzDQotIEpvaW4gRmllbGQgPSBUcmFjdA0KLSBUYXJnZXQgZmllbGQgPSBOQU1FDQoNCkxlYXZlIHRoZSAiQ2FjaGUgam9pbiBsYXllciBpbiBtZW1vcnkiIGNoZWNrZWQgYW5kIHNjcm9sbCBkb3duIHRvICJKb2luZWQgRmllbGRzIi4gQ2xpY2sgYWxsIG9mIHRoZSBmaWVsZHMgYW5kIHNjcm9sbCBkb3duIHRvIHRoZSAiQ3VzdG9tIGZpZWxkIG5hbWUgcHJlZml4IiBvcHRpb24gYW5kIGNoZWNrIHRoZSBib3guIFJlbW92ZSBhbGwgb2YgdGhlIHRleHQgaW4gdGhlIGJveCBhbmQgdGhlbiBjbGljayBPSy4NCg0KPHAgYWxpZ249ImNlbnRlciI+PGltZyBzcmM9ICJJbWFnZXMvcWdpcy12ZWN0b3Itam9pbi1kaWFsb2cucG5nIiBhbHQ9IlZlY3RvciBKb2luIFdpbmRvdyIgc3R5bGU9IndpZHRoOjg1JSI+PC9wPg0KDQpCZSBzdXJlIHRvIGNsaWNrIE9LIG9uIHRoZSBwcm9wZXJ0aWVzIHdpbmRvdyBhcyB3ZWxsIHRvIGNvbXBsZXRlIHRoZSBqb2luLiBGaW5hbGx5LCBvcGVuIHRoZSBhdHRyaWJ1dGUgdGFibGUgZm9yIHRoZSBjZW5zdXMgdHJhY3RzIGFuZCBzY3JvbGwgdG8gdGhlIGZhciByaWdodCBvZiB0aGUgdGFibGUuIElmIHRoZSBqb2luIHdvcmtlZCBwcm9wZXJseSB5b3Ugc2hvdWxkIHNlZSBhIG51bWJlciBvZiBhZGRpdGlvbmFsIGZpZWxkcyBhZGRlZCB0byB0aGUgdGFibGUuDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxkaXYgY2xhc3M9Inpvb20iPjxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtam9pbi10YWJsZS5wbmciIGFsdD0iSm9pbiBUYWJsZSIgc3R5bGU9IndpZHRoOjEwMCUiPjwvZGl2PjwvcD4NCg0KVGhpcyB3aWxsIHByb3ZpZGUgYWxsIG9mIHRoZSBkYXRhIGFuZCBpbmZvcm1hdGlvbiB5b3UgbmVlZCB0byB2aXN1YWxpemUgdGhlIGRhdGEgYW5kIG1ha2UgY29tcGFyaXNvbnMgb2YgdGhlIHdhdGVyc2hlZHMuDQoNCjxiaWc+PGI+UXVlc3Rpb24gTm8uIDI8L2I+PC9iaWc+DQo8YmxvY2txdW90ZT4NCkhvdyBtYW55IHdhdGVyc2hlZHMgY292ZXIgTW9udGdvbWVyeSBDb3VudHk/IEFsdGhvdWdoIHRoZXkgaGF2ZSBiZWVuIGNsaXBwZWQgZnJvbSB0aGVpciBvcmlnaW5hbCBnZW9tZXRyeSwgd2hpY2ggd2F0ZXJzaGVkIGlzIHRoZSBsYXJnZXN0PyBXaGljaCBpcyB0aGUgc21hbGxlc3Q/DQo8L2Jsb2NrcXVvdGU+DQoNCjwvZGV0YWlscz4NCjxocj48L2hyPg0KDQo8ZGV0YWlscz4NCjxzdW1tYXJ5PjxiaWc+VmlldyBEaXJlY3Rpb25zIGluIDxiPiBbUl17c3R5bGU9ImNvbG9yOiM2NDk1RUQifSA8L2I+PC9iaWc+PC9zdW1tYXJ5Pg0KDQpUaGVyZSBhcmUgc29tZSBhZGRpdGlvbmFsIHByb2Nlc3Npbmcgc3RlcHMgbmVlZGVkIG9uIHRoZSBjb2xsZWN0ZWQgZGF0YXNldHMgYmVmb3JlIHlvdSBjYW4gbW92ZSBvbiB0byB0aGUgdmlzdWFsaXphdGlvbnMuIEluIFtFeGVyY2lzZSAzLCBTdGVwIDJdKGh0dHBzOi8vY2hyaXNtZ2VudHJ5LmdpdGh1Yi5pby9HSVMxLUV4ZXJjaXNlLTMvIzEyX1N0ZXBfVHdvOl9UaGVfQW5hbHlzZXMpIHlvdSB1c2VkIHRoZSBgbWVyZ2VgIGZ1bmN0aW9uIHRvIGNvbWJpbmVkIHRoZSBjZW5zdXMgdHJhY3RzIGFuZCBwb3B1bGF0aW9uIGRhdGEuIEluIHRoaXMgZXhlcmNpc2UgeW91IHdpbGwgcmVwZWF0IHRob3NlIHN0ZXBzIHRvIGNvbm5lY3QgdGhlIF9kZW1vZ3JhcGhpY3NfIGRhdGFzZXQgdG8gdGhlIGNlbnN1cyB0cmFjdHMuDQoNCmBgYHtyIGFkZCBkZW1vZ3JhcGhpY3MgZGF0YSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KY2Vuc3VzX3RyYWN0cyA8LSBtZXJnZSh4ID0gbW9udGNvX3RyYWN0cywgeSA9IGRlbW9ncmFwaGljcywgYnkueCA9ICJOQU1FIiwgYnkueSA9ICJUcmFjdCIsIGFsbCA9IFRSVUUpDQpgYGANCg0KQnkgcGxvdHRpbmcgdGhlIF9icm93bmZpZWxkXyBvciBfd2F0ZXJzaGVkc18gZGF0YSB1c2luZyBgZ2dwbG90MmAgb3IgcXVpY2tseSB1c2luZyBgcGxvdCh4KWAgd2hlcmUgeCA9IHRoZSBuYW1lIG9mIHRoZSBkYXRhc2V0LCB5b3Ugd2lsbCBsaWtlIGJlIGFibGUgdG8gZGV0ZXJtaW5lIHRoYXQgdGhlIGRhdGEgaW5jbHVkZWQgZXh0ZW5kcyBmYXIgYmV5b25kIHRoZSBib3VuZGFyaWVzIG9mIE1vbnRnb21lcnkgQ291bnR5LiBJbiB0aGUgcHJldmlvdXMgW2V4ZXJjaXNlXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS00LyMxMl9TdGVwX1R3bzpfVGhlX0FuYWx5c2VzKSB0aGUgYGludGVyc2VjdGAgZnVuY3Rpb24gd2FzIHVzZWQgdG8gY2xpcCBvdXQgdGhlIGNvdW50aWVzIHdpdGhpbiB0aGUgaHVycmljYW5lIGJ1ZmZlci4gSW4gdGhpcyBleGVyY2lzZSB5b3Ugd2lsbCB1c2UgdGhlIGBjcm9wYCBmdW5jdGlvbiB0byBzZWUgaG93IGl0IHZhcmllcyBmcm9tIGBpbnRlcnNlY3RgLiBGb3IgdGhpcyBzdGVwIHlvdSB3aWxsIHdhbnQgdG8gY3JvcCB0aGUgYnJvd25maWVsZHMgYW5kIHdhdGVyc2hlZHMgZGF0YXNldHMgYnkgdGhlIGNlbnN1cyB0cmFjdHMgdG8gcmV0YWluIG9ubHkgdGhvc2Ugd2l0aGluIHRoZSBjb3VudHkuDQoNCmBgYHtyIGNyb3AgZGF0YSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KbW9udGNvX2Jyb3duZmllbGRzIDwtIGNyb3AoYnJvd25maWVsZHNfZGF0YSxjZW5zdXNfdHJhY3RzKQ0KbW9udGNvX3dhdGVyc2hlZHMgPC0gY3JvcCh3YXRlcnNoZWRzX2RhdGEsY2Vuc3VzX3RyYWN0cykNCmBgYA0KDQpJZiB5b3UgY3JlYXRlIGEgYGdncGxvdCgpYCBvZiB0aGUgZGF0YSB5b3Ugd2lsbCBzZWUgaG93IHRoZSBkYXRhc2V0cyB3ZXJlIHN1YnNldC4gRXNzZW50aWFsbHksIGEgYm91bmRpbmcgYm94IChleHRlbnQgb2YgdGhlIGRhdGFzZXQgZnJvbSB0aGUgbW9zdCB1cHBlci1sZWZ0IHBvcnRpb24gdG8gdGhlIGxvd2VyLXJpZ2h0KSB3YXMgY3JlYXRlZCBmb3IgdGhlIGNlbnN1cyB0cmFjdCBkYXRhIGFuZCBhbnkgZGF0YSB3aXRoaW4gdGhhdCBib3ggd2FzIHJldGFpbmVkLiBXaHkgbWlnaHQgdGhpcyBwb3RlbnRpYWxseSBiZSBwcm9ibGVtYXRpYyBpbiBzb21lIGluc3RhbmNlcz8gSW4gd2hhdCBpbnN0YW5jZSBtaWdodCB0aGlzIGJlIHRoZSBiZXN0IG1ldGhvZD8NCg0KQmVmb3JlIHByb2NlZWRpbmcgdG8gdGhlIHZpc3VhbGl6YXRpb24gcG9ydGlvbiB5b3UgbmVlZCB0byBjcmVhdGUgYSBjb3VwbGUgdGFibGVzIHRvIGhlbHAgYW5zd2VyIHRoZSBxdWVzdGlvbnMgYXNrZWQgYnkgeW91ciBjb21tdW5pdHkgcGFydG5lcnMuIE9uZSBiZWluZyBob3cgbWFueSBicm93bmZpZWxkIG9jY3VyIHdpdGhpbiBlYWNoIHdhdGVyc2hlZCBhbmQgY2Vuc3VzIHRyYWN0LiBUbyBkbyB0aGlzIHlvdSBjYW4gdXNlIHRoZSBgb3ZlcmAgZnVuY3Rpb24gZnJvbSB0aGUgYHJnZW9zYCB0byBjcmVhdGUgYSBjb3VudCBvZiB0aGUgb3ZlcmxhcHBpbmcgZGF0YS4gVGhpcyBpcyBjYWxsZWQgYSBfc3BhdGlhbCBqb2luXyBhbmQgaXQgcmV0dXJucyBhIGNvdW50IG9mIHRoZSBwb2ludHMgdGhhdCBmYWxsIHdpdGhpbiBhIHNwZWNpZmljIHBvbHlnb24uIE1vcmUgaW5mb3JtYXRpb24gb24gYG92ZXJgIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3JnZW9zL3ZlcnNpb25zLzAuNS01L3RvcGljcy9vdmVyKS4NCg0KYGBge3Igc3BhdGlhbCBqb2luIHdpdGggd2F0ZXJzaGVkcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KYnJvd25maWVsZHNfcGVyX3dhdGVyc2hlZCA8LSBvdmVyKG1vbnRjb19icm93bmZpZWxkcyxtb250Y29fd2F0ZXJzaGVkcykNCndhdGVyc2hlZF90YWJsZSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGJyb3duZmllbGRzX3Blcl93YXRlcnNoZWQkSFVDXzEyKSkNCndhdGVyc2hlZF90YWJsZSA8LSB0cmFuc2Zvcm0od2F0ZXJzaGVkX3RhYmxlLCBWYXIxID0gYXMuY2hhcmFjdGVyKFZhcjEpKQ0KY29sbmFtZXMod2F0ZXJzaGVkX3RhYmxlKSA8LSBjKCJIVUNfMTIiLCJCRl9Db3VudCIpDQp3YXRlcnNoZWRfdGFibGUNCmBgYA0KDQpJbiB0aGUgc2NyaXB0IGFib3ZlLCBgb3ZlcmAgY3JlYXRlZCB0aGUgc3BhdGlhbCBqb2luIGFuYWx5c2lzLiBUaGUgbmV4dCBsaW5lIGNvbnZlcnRlZCB0aGUgaW5mb3JtYXRpb24gaW50byBhIGRhdGFmcmFtZSB0YWJsZSB3aXRoIGNvbHVtbnMgb2YgdmFyaWFibGVzIGFuZCByb3dzIG9mIG9ic2VydmF0aW9ucy4gSG93ZXZlciwgYmVjYXVzZSB0aGUgd2F0ZXJzaGVkIG5hbWVzIChIVUNfMTIpIGEgbnVtZXJpYywgdGhlIHRhYmxlIHdvdWxkIG5vdCBiZSBhYmxlIHRvIGJlIGpvaW5lZCB0byBhIHByZXZpb3VzIGRhdGFzZXQgYmVjYXVzZSB0aGUgbnVtZXJpYyBuYW1lIGZvciB0aGUgd2F0ZXJzaGVkIHdhcyB0cmVhdGVkIGFzIGEgY2hhcmFjdGVyIChub21pbmFsIGRhdGEpLiBTbyB0aGUgYHRyYW5zZm9ybWAgZnVuY3Rpb24gd2FzIHVzZWQgdG8gY29udmVydCB0aGUgbmFtZXMgdG8gY2hhcmFjdGVycy4gRmluYWxseSwgYGNvbG5hbWVzYCB3YXMgdXNlZCB0byByZW5hbWUgdGhlIGNvbHVtbnMgdG8gbmFtZXMgdGhhdCBhcmUgbW9yZSBhcHByb3ByaWF0ZSBmb3IgdGhlIGRhdGEuDQoNCk9uY2UgdGhlIHRhYmxlIGhhcyBiZWVuIGNyZWF0ZWQgeW91IHdpbGwgbmVlZCB0byBjb25uZWN0IHRoZSB0YWJsZSB0byB0aGUgb3JpZ2luYWwgZGF0YSBzbyB0aGUgaW5mb3JtYXRpb24gY2FuIHBvdGVudGlhbGx5IGJlIGluY2x1ZGVkIGluIHRoZSB2aXN1YWxpemF0aW9uLiBCZWNhdXNlIHNvbWUgb2YgdGhlIHdhdGVyc2hlZCBkbyBubyBjb250YWluIGEgYnJvd25maWVsZCB0aGVyZSB3aWxsIGJlIE5BIHZhbHVlcyByZXBvcnRlZCBmb3IgdGhvc2Ugb2JzZXJ2YXRpb25zLiBTbyB0aGVyZSB3aWxsIGJlIGEgbGluZSBhZGRlZCB0byByZXBsYWNlIHRoZSBOQSB2YWx1ZXMgd2l0aCB6ZXJvcyBpbiB0aGUgc2NyaXB0IGJlbG93Og0KDQpgYGB7ciBjb25uZWN0IHRhYmxlIHRvIHdhdGVyc2hlZHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0NCm1vbnRjb193YXRlcnNoZWRfZGF0YSA8LSBtZXJnZSh4ID0gbW9udGNvX3dhdGVyc2hlZHMsIHkgPSB3YXRlcnNoZWRfdGFibGUsIGJ5LnggPSAiSFVDXzEyIiwgYnkueSA9ICJIVUNfMTIiLCBhbGwgPSBUUlVFKQ0KbW9udGNvX3dhdGVyc2hlZF9kYXRhQGRhdGEkQkZfQ291bnRbaXMubmEobW9udGNvX3dhdGVyc2hlZF9kYXRhQGRhdGEkQkZfQ291bnQpXSA8LSAwDQptb250Y29fd2F0ZXJzaGVkX2RhdGFAZGF0YQ0KYGBgDQoNCldoaWxlIHlvdSBoYXZlIHNlZW4gdGhlIGBtZXJnZWAgZnVuY3Rpb24gYmVmb3JlLCBub3RpY2UgdGhlIHN5bnRheCBmb3IgdGhlIHNlY29uZCBsaW5lLiBCZWNhdXNlIHRoZSBkYXRhIGlzIGEgU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIHRoZSBkYXRhIHRhYmxlIHRoYXQgY29udGFpbnMgdGhlIGRhdGEgd2lsbCBiZSBoZWxkIGluIGEgX3Nsb3RfIChhIGNvbnRhaW5lciBmb3IgaW5mb3JtYXRpb24gaW4gY2VydGFpbiBmaWxlIHR5cGVzKSBjYWxsICoqZGF0YSoqLiBTbyB0byBleGFtaW5lIHRoZSBpbmZvcm1hdGlvbiB5b3Ugd2lsbCBjYWxsIHRvIHRoZSBvYmplY3QgYW5kIGFkZCBfQGRhdGFfIGZvbGxvd2luZyB0aGUgb2JqZWN0IG5hbWUuIEluIHRoZSBleGFtcGxlIGFib3ZlLCB0aGUgc2NyaXB0IGlzIGlkZW50aWZ5aW5nIHRoZSAqKkJGX0NvdW50KiogdmFyaWFibGUgaW4gdGhlIHdhdGVyc2hlZHMgZGF0YSBzbG90IGFuZCBzYXlpbmcgImlmIHRoZXJlIF9pc18gYSBfbmFfIHZhbHVlIGluIHRoYXQgdmFyaWFibGUgd2l0aGluIHRoZSBzbG90LCBpdCBzaG91bGQgYmUgcmVwbGFjZWQgd2l0aCBhIDAuIiBJZiB5b3UgZXhhbWluZSB0aGUgb2JqZWN0IG9ubHkgeW91IHdpbGwgbm90aWNlIHRoZXJlIGFyZSBhY3R1YWxseSBzZXZlcmFsIHNsb3RzIGluY2x1ZGluZzoNCg0KLSBiYiA9IGJvdW5kaW5nIGJveA0KLSBkYXRhID0gdGhlIGRhdGEgdGFibGUNCi0gcGxvdE9yZGVyID0gdGhlIG9yZGVyIG9mIHRoZSBwb2x5Z29ucyB3aGVuIGRyYXduDQotIHBvbHlnb25zID0gdGhlIGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUgdmFsdWVzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGRpZmZlcmVudCBwb2x5Z29ucw0KLSBwcm9qNHN0cmluZyA9IHRoZSBjcnMgaW5mb3JtYXRpb24NCg0KUmVtZW1iZXIgdGhhdCB5b3Ugc2hvdWxkIGFsd2F5cyBleGFtaW5lIG5ldyBkYXRhc2V0cyB3aGVuIHRoZXkgYXJlIGltcG9ydGVkIGludG8geW91ciBwcm9qZWN0LiBCZWNhdXNlIHRoZSBjZW5zdXMgdHJhY3QgZGF0YSBpcyBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXQgdGhhbiB0aGUgd2F0ZXJzaGVkIHlvdSB3aWxsIGNvbXBsZXRlIGEgdmVyeSBzaW1pbGFyIHByb2Nlc3MgdG8gdGhlIGFib3ZlIHNjcmlwdCB3aXRoIGEgc2xpZ2h0IG1vZGlmaWNhdGlvbiB0byBjb252ZXJ0IHRoZSBjZW5zdXMgdHJhY3RzIHRvIGEgU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lLg0KDQpgYGB7ciBjcmVhdGUgdHJhY3RzIHRhYmxlLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9DQpjZW5zdXNfdHJhY3RzX3NwZGYgPC0gc2Y6OmFzX1NwYXRpYWwoY2Vuc3VzX3RyYWN0cykNCmJyb3duZmllbGRzX3Blcl90cmFjdCA8LSBvdmVyKG1vbnRjb19icm93bmZpZWxkcyxjZW5zdXNfdHJhY3RzX3NwZGYpDQpjZW5zdXNfdHJhY3RfdGFibGUgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShicm93bmZpZWxkc19wZXJfdHJhY3QkTkFNRSkpDQpjZW5zdXNfdHJhY3RfdGFibGUgPC0gdHJhbnNmb3JtKGNlbnN1c190cmFjdF90YWJsZSwgVmFyMSA9IGFzLmNoYXJhY3RlcihWYXIxKSwgRnJlcSA9IGFzLm51bWVyaWMoRnJlcSkpDQpjb2xuYW1lcyhjZW5zdXNfdHJhY3RfdGFibGUpIDwtIGMoIk5hbWUiLCJCRl9Db3VudCIpDQpjZW5zdXNfdHJhY3RfdGFibGUNCmBgYA0KDQpXaXRoIHRoZSB0YWJsZSBjcmVhdGVkIHlvdSBjYW4gbm93IGF0dGFjaCBpdCB0byB0aGUgb3JpZ2luYWwgY2Vuc3VzIGRhdGEuDQoNCmBgYHtyIGNvbm5lY3QgdG8gdHJhY3RzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9DQpjZW5zdXNfdHJhY3RfZGF0YXNldCA8LSBtZXJnZSh4ID0gY2Vuc3VzX3RyYWN0cywgeSA9IGNlbnN1c190cmFjdF90YWJsZSwgYnkueCA9ICJOQU1FIiwgYnkueSA9ICJOYW1lIiwgYWxsID0gVFJVRSkNCmNlbnN1c190cmFjdF9kYXRhc2V0JEJGX0NvdW50W2lzLm5hKGNlbnN1c190cmFjdF9kYXRhc2V0JEJGX0NvdW50KV0gPC0gMA0Kc3RyKGNlbnN1c190cmFjdF9kYXRhc2V0KQ0KYGBgDQoNCndoaWxlIHlvdSBjb3VsZCBoYXZlIGtlcHQgdGhlIFNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZSB2ZXJzaW9uIG9mIHRoZSBjZW5zdXMgZGF0YSwgaXQgaXMgaW1wb3J0YW50IHRvIGtub3cgaG93IHRvIG1hbmFnZSBkaWZmZXJlbnQgY2xhc3NlcyBvZiBkYXRhLiBTbyBpbiB0aGlzIGV4ZXJjaXNlIHRoZSBjZW5zdXMgdHJhY3QgZGF0YSB3aWxsIGNvbnRpbnVlIHRvIGJlIFtzaW1wbGUgZmVhdHVyZXMgKHNmKV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3NmL3ZpZ25ldHRlcy9zZjEuaHRtbCkgZGF0YSB3aGlsZSB0aGUgd2F0ZXJzaGVkIGRhdGEgd2lsbCBiZSBbc3BdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9zcC92aWduZXR0ZXMvaW50cm9fc3AucGRmKS4NCg0KSWYgeW91IGV4YW1pbmUgdGhlIGJyb3duZmllbGRzIGRhdGFzZXQgaXQgaXMgYWxzbyBhIHR5cGUgb2YgX3NwXyBkYXRhIGNhbGxlZCBhICoqU3BhdGlhbFBvaW50c0RhdGFGcmFtZSoqLiBCZWNhdXNlIHRoZSB2YWx1ZXMgYXJlIHBvaW50cyBhbmQgbm90IHBvbHlnb25zIHlvdSBjYW4gc2VlIHRoZSB0eXBlIGNoYW5nZXMgYWNjb3JkaW5nbHkuIElmIHlvdSBjcmVhdGUgYSB2aXN1YWxpemF0aW9uIG9mIHRoZSBkYXRhIHlvdSB3aWxsIGZpbmQgdGhhdCB3aGlsZSBjcm9wIHdvcmtlZCB0byBzdWJzZXQgdGhlIGluZm9ybWF0aW9uIGJhc2VkIG9uIHRoZSBib3VuZGluZyByZWN0YW5nbGUgb2YgdGhlIGNlbnN1cyB0cmFjdHMsIGJlY2F1c2Ugb2YgdGhlIHNoYXBlIG9mIE1vbnRnb21lcnkgQ291bnR5IGFuZCB0aGUgbG9jYXRpb24gb2YgdGhlIGJyb3duZmllbGRzIG9uZSByZWNvcmQgd2FzIHJldGFpbmVkIGVycm9uZW91c2x5LiBUaGUgZmlyc3QgcmVjb3JkICJUaGUgQ29tcG9zdCBDb21wYW55IiBpcyBsb2NhdGVkIHNvdXRoIG9mIHRoZSBjb3VudHkgYW5kIHRoZXJlZm9yZSBuZWVkcyB0byBiZSByZW1vdmVkIGZyb20gdGhlIGRhdGFzZXQuIFRvIGRvIHRoaXMgeW91IHdpbGwgY29udmVydCB0aGUgYnJvd25maWVsZHMgZGF0YXNldCB0byBhIGRhdGEgZnJhbWUgYW5kIHJlbW92ZSB0aGUgZmlyc3Qgcm93IG9mIGRhdGEuIEJlY2F1c2UgaXRlbXMgaW4gYSBkYXRhIGZyYW1lIGNhbiBiZSBpZGVudGlmaWVkIGJ5IHJvdyAoZmlyc3QgdmFsdWUpIGFuZCBjb2x1bW4gKHNlY29uZCB2YWx1ZSkgc2ltcGx5IGFkZGluZyBbLTEsXSBiZWhpbmQgdGhlIG9iamVjdCBuYW1lIHdpbGwgInN1YnJ0cmFjdCIgdGhlIGVudGlyZSByb3cgZnJvbSB0aGUgZGF0YXNldC4gU2luY2UgeW91IGFyZSBhbHJlYWR5IGVkaXRpbmcgdGhlIGRhdGEsIGl0IHdvdWxkIGFsc28gbWFrZSBzZW5zZSB0byByZW5hbWUgdGhlIGNvbHVtbiB0byBuYW1lcyB0aGF0IG1hdGNoIGBnZ3Bsb3QyYCBub21lbmNsYXR1cmUuDQoNCmBgYHtyIGNvbnZlcnQgZml4IHJlbmFtZSBicm93bmZpZWxkcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KYnJvd25maWVsZHNfZGF0YXNldCA8LSBhcy5kYXRhLmZyYW1lKG1vbnRjb19icm93bmZpZWxkcykNCmNvbG5hbWVzKGJyb3duZmllbGRzX2RhdGFzZXQpIDwtIGMoIk5hbWUiLCAibG9uZyIsICJsYXQiLCAiTkEiKQ0KYnJvd25maWVsZHNfZGF0YXNldCA8LSBicm93bmZpZWxkc19kYXRhc2V0Wy0xLF0NCmJyb3duZmllbGRzX2RhdGFzZXQNCmBgYA0KDQpGaW5hbGx5LCBqdXN0IGluIGNhc2UgeW91IG5lZWQgYSBzaW1wbGUgb3V0bGluZSBvZiBNb250Z29tZXJ5IENvdW50eSBmb3IgeW91ciB2aXN1YWxpemF0aW9uIGluIHRoZSBuZXh0IHN0ZXAgeW91IGNhbiBjcmVhdGUgYW4gb2JqZWN0IHBvbHlnb24gb2YgdGhlIGNvdW50eSB3aXRoIGEgc2ltaWxhciBzY3JpcHQgdG8gY3JlYXRlIHRoZSBzdGF0ZXMgaW5mb3JtYXRpb24gaW4gW0V4ZXJjaXNlIDIsIFN0ZXAgMV0oaHR0cHM6Ly9jaHJpc21nZW50cnkuZ2l0aHViLmlvL0dJUzEtRXhlcmNpc2UtMi8jMTFfU3RlcF9PbmU6X1RoZV9EYXRhKS4NCg0KYGBge3IgY3JlYXRlIG1vbnRnb21lcnkgY291bnR5IHBvbHlnb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0NCmNvdW50aWVzIDwtIG1hcF9kYXRhKCJjb3VudHkiKQ0KdG5fY291bnRpZXMgPC0gc3Vic2V0KGNvdW50aWVzLCByZWdpb24gPT0gInRlbm5lc3NlZSIpDQptb250Y28gPC0gc3Vic2V0KHRuX2NvdW50aWVzLCBzdWJyZWdpb24gPT0gIm1vbnRnb21lcnkiKQ0KYGBgDQoNCjxiaWc+PGI+UXVlc3Rpb24gTm8uIDI8L2I+PC9iaWc+DQo8YmxvY2txdW90ZT4NCkhvdyBtYW55IHdhdGVyc2hlZHMgY292ZXIgTW9udGdvbWVyeSBDb3VudHk/IEFsdGhvdWdoIHRoZXkgaGF2ZSBiZWVuIGNsaXBwZWQgZnJvbSB0aGVpciBvcmlnaW5hbCBnZW9tZXRyeSwgd2hpY2ggd2F0ZXJzaGVkIGlzIHRoZSBsYXJnZXN0PyBXaGljaCBpcyB0aGUgc21hbGxlc3Q/DQo8L2Jsb2NrcXVvdGU+DQo8c21hbGw+SElOVDogVmlldyBhY3JlcyBpbiB0aGUgd2F0ZXJzaGVkIGRhdGFzZXQuPC9zbWFsbD4NCjwvZGV0YWlscz4NCg0KIyMgU3RlcCBUaHJlZTogVGhlIFZpc3VhbGl6YXRpb24NCg0KSW4gdGhpcyBzdGVwIHlvdSB3aWxsIG5lZWQgdG8gZXhhbWluZSB0aGUgc3BhdGlhbCBkaXN0cmlidXRpb24gb2YgYnJvd25maWVsZHMgd2l0aGluIHRoZSB3YXRlcnNoZWRzIG9mIE1vbnRnb21lcnkgQ291bnR5IGFuZCBtYWtlIHNvbWUgcXVhbGl0YXRpdmUgaW50ZXJwcmV0YXRpb25zIG9mIHBvdGVudGlhbGx5IGltcGFjdGVkIHVyYmFuIGFyZWFzLiANCg0KPGRldGFpbHM+PHN1bW1hcnk+PGJpZz5WaWV3IGRpcmVjdGlvbnMgaW4gPGI+IFtBcmNHSVMgUHJvXXtzdHlsZT0iY29sb3I6I2ZmNDUwMCJ9IDwvYj48L3NwYW4+PC9iaWc+PC9zdW1tYXJ5Pg0KDQpFeGFtaW5lIHRoZSBzcGF0aWFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgYnJvd25maWVsZCB0aHJvdWdob3V0IHRoZSBjb3VudHkuIFRoZSBjbHVzdGVyaW5nIHNob3VsZCBiZSByZWxhdGl2ZWx5IGFwcGFyZW50IGFuZCBtaWdodCBtYXRjaCB1cCB3aXRoIHlvdXIga25vd2xlZGdlIG9mIGluZHVzdHJpYWwgYWN0aXZpdGllcyBpbiB0aGUgdmFyaW91cyBhcmVhcyBvZiBNb250Z29tZXJ5IENvdW50eS4gSW4gb3JkZXIgdG8gaGVscCBxdWFudGlmeSB0aGUgbnVtYmVyIG9mIGJyb3duZmllbGRzIGluIGVhY2ggd2F0ZXJzaGVkIHlvdSBjYW4gdXNlIGEgKipTcGF0aWFsIGpvaW4qKiB0byBjcmVhdGUgYSBjb3VudCB2YXJpYWJsZSBmb3IgdGhpcyBpbmZvcm1hdGlvbi4gVG8gZG8gdGhpcywgcmlnaHQtY2xpY2sgb24gdGhlIF9tb250Z29tZXJ5IGNvdW50eSB3YXRlcnNoZWRfIGRhdGFzZXQgYW5kIGdvIHRvIF9Kb2luIGFuZCBSZWxhdGVzID4gU3BhdGlhbCBKb2luXw0KDQo8cCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0gIkltYWdlcy9hcmNnaXMtc3BhdGlhbC1qb2luLnBuZyIgYWx0PSJTcGF0aWFsIEpvaW4gRGF0YXNldHMiIHN0eWxlPSJ3aWR0aDo4NSUiPjwvcD4NCg0KSW4gdGhlIHJlc3VsdGluZyB3aW5kb3csIHNlbGVjdCB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgKHlvdXIgZmlsZSBuYW1lcyBtYXkgdmFyeSk6DQoNCi0gVGFyZ2V0IEZlYXR1cmVzID0gTW9udGdvbWVyeSBDb3VudHkgd2F0ZXJzaGVkcw0KLSBKb2luIEZlYXR1cmVzID0gTW9udGdvbWVyeSBDb3VudHkgYnJvd25maWVsZHMNCi0gT3V0cHV0IEZlYXR1cmUgQ2xhc3MgPSBUaGlzIGlzIHdoZXJlIHlvdSBuYW1lIHRoZSBuZXcgZGF0YXNldC4gRm9yIGNvbnRpbnVpdHkgeW91IGNhbiBuYW1lIGl0IHNvbWV0aGluZyBsaWtlOiBicm93bmZpZWxkc19wZXJfd2F0ZXJzaGVkLnNocA0KLSBKb2luIE9wZXJhdGlvbiA9IENob29zZSAiSm9pbiBvbmUgdG8gb25lIiBmcm9tIHRoZSBkcm9wLWRvd24gbWVudQ0KICAtIEtlZXAgYWxsIFRhcmdldCBGZWF0dXJlcyBzaG91bGQgcmVtYWluIGNoZWNrZWQNCi0gTWF0Y2ggT3B0aW9uID0gQ2hvb3NlICJJbnRlcnNlY3QiIGZyb20gdGhlIGRyb3AtZG93biBtZW51DQoNCllvdSBjYW4gbGVhdmUgdGhlIHJlbWFpbmluZyBpdGVtcyBibGFuayBhbmQgY2xpY2sgT0suDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxpbWcgc3JjPSAiSW1hZ2VzL2FyY2dpcy1zcGF0aWFsLWpvaW4tcGFuZS5wbmciIGFsdD0iU3BhdGlhbCBKb2luIERhdGFzZXRzIERpYWxvZyIgc3R5bGU9IndpZHRoOjg1JSI+PC9wPg0KDQpCeSBleGFtaW5pbmcgdGhlIGF0dHJpYnV0ZSB0YWJsZSBmb3IgdGhlIG5ldyBkYXRhc2V0IHlvdSBzaG91bGQgc2VlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCAqKkpvaW5fQ291bnQqKi4gVGhpcyBpcyB0aGUgbnVtYmVyIG9mIGJyb3duZmllbGRzIHRoYXQgb2NjdXIgd2l0aGluIGVhY2ggd2F0ZXJzaGVkLg0KIA0KVXNpbmcgdGhlIHNraWxscyB5b3UgbGVhcm5lZCBpbiBFeGVyY2lzZXMgW1R3b10oaHR0cHM6Ly9jaHJpc21nZW50cnkuZ2l0aHViLmlvL0dJUzEtRXhlcmNpc2UtMi8pLCBbVGhyZWVdKGh0dHBzOi8vY2hyaXNtZ2VudHJ5LmdpdGh1Yi5pby9HSVMxLUV4ZXJjaXNlLTMvKSwgYW5kIFtGb3VyXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS00LykgeW91IGNhbiBub3cgbWFrZSBhIG1hcCB0aGF0IHNob3dzIE1vbnRnb21lcnkgQ291bnR5LCB0aGUgbG9jYXRpb24gb2YgYnJvd25maWVsZHMgYW5kIHdhdGVyc2hlZHMgaW4gYSBncmFkdWF0ZWQgY29sb3Igc2NoZW1lIGJ5IG51bWJlciBvZiBicm93bmZpZWxkcy4gUmVtZW1iZXIgdG8gaW5jbHVkZSBjYXJ0b2dyYXBoaWMgZWxlbWVudHMgc3VjaCBhcyBsZWdlbmQsIHNjYWxlIGJhciwgbm9ydGggYXJyb3csIGV0Yy4gSW4gdGhpcyB2aXN1YWxpemF0aW9uIHlvdSBtYXkgYWxzbyB3YW50IHRvIGFkZCBhIGRpZmZlcmVudCBiYXNlbWFwIG9yIGluc2V0IG1hcCB0aGF0IHByb3ZpZGVzIGFkZGl0aW9uYWwgc3VwcG9ydGluZyBpbmZvcm1hdGlvbi4NCg0KPGJpZz48Yj5RdWVzdGlvbiBOby4gMzwvYj48L2JpZz4NCjxibG9ja3F1b3RlPg0KV2hpY2ggd2F0ZXJzaGVkIGNvbnRhaW5zIHRoZSBtb3N0IGJyb3duZmllbGRzPw0KPC9ibG9ja3F1b3RlPg0KDQo8L2RldGFpbHM+DQo8aHI+PC9ocj4NCg0KPGRldGFpbHM+PHN1bW1hcnk+PGJpZz5WaWV3IGRpcmVjdGlvbnMgaW4gPGI+IFtRR0lTXXtzdHlsZT0iY29sb3I6IzAwNjQwMCJ9IDwvYj48L3NwYW4+PC9iaWc+PC9zdW1tYXJ5Pg0KDQpFeGFtaW5lIHRoZSBzcGF0aWFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgYnJvd25maWVsZCB0aHJvdWdob3V0IHRoZSBjb3VudHkuIFRoZSBjbHVzdGVyaW5nIHNob3VsZCBiZSByZWxhdGl2ZWx5IGFwcGFyZW50IGFuZCBtaWdodCBtYXRjaCB1cCB3aXRoIHlvdXIga25vd2xlZGdlIG9mIGluZHVzdHJpYWwgYWN0aXZpdGllcyBpbiB0aGUgdmFyaW91cyBhcmVhcyBvZiBNb250Z29tZXJ5IENvdW50eS4gSW4gb3JkZXIgdG8gaGVscCBxdWFudGlmeSB0aGUgbnVtYmVyIG9mIGJyb3duZmllbGRzIGluIGVhY2ggd2F0ZXJzaGVkIHlvdSBjYW4gdXNlICoqSm9pbiBhdHRyaWJ1dGVzIGJ5IGxvY2F0aW9uIChTdW1tYXJ5KSoqIGZyb20gdGhlIF9WZWN0b3IgR2VuZXJhbF8gbWVudSBpbiB0aGUgUHJvY2Vzc2luZyBUb29sYm94LiB0aGlzIHdpbGwgY3JlYXRlIGEgY291bnQgb2YgdGhlIHRvdGFsIG51bWJlciBvZiBicm93bmZpZWxkcyBwZXIgd2F0ZXJzaGVkIHBvbHlnb24uIEluIHRoZSBfSm9pbiBhdHRyaWJ1dGVzIGJ5IGxvY2F0aW9uIChTdW1tYXJ5KV8gc2VsZWN0IHRoZSBmb2xsb3dpbmcgb3B0aW9ucyAobGF5ZXIgbmFtZXMgbWF5IHZhcnkpOg0KDQotIElucHV0IGxheWVyID0gd2F0ZXJzaGVkIGxheWVyIGZvciBNb250Z29tZXJ5IENvdW50eQ0KLSBKb2luIGxheWVyID0gYnJvd25maWVsZHMgbGF5ZXIgZm9yIE1vbnRnb21lciBDb3VudHkNCi0gR2VvbWV0cmljIHByZWRpY2F0ZSA9IEludGVyc2VjdHMNCg0KSW4gdGhlIF9TdW1tYXJpZXMgdG8gY2FsY3VsYXRlLi4uXyB5b3Ugd2lsbCBjbGljayB0aGUgYnJvd3NlIGJ1dHRvbiBhbmQgc2VsZWN0IG9ubHkgImNvdW50Ii4gV2hlbiBzZWxlY3RlZCwgY2xpY2sgdGhlIGJsdWUgYXJyb3cgYnV0dG9uIDxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtYmx1ZS1hcnJvdy5qcGciIGFsdD0iYmx1ZSBBcnJvdyIgd2lkdGggPSAiMjAiIGhlaWdodCA9ICIyMCI+IHRvIHJldHVybiB0byB0aGUgcHJldmlvdXMgcGFnZS4gQXMgYmVmb3JlLCB5b3UgY2FuIGxlYXZlIHRoaXMgYXMgYSB0ZW1wb3JhcnkgZmlsZVwqIG9yIHlvdSBjYW4gY2hvb3NlIHRvIGNyZWF0ZSBhIHBlcm1hbmVudCBmaWxlIGZvciBmdXR1cmUgdXNlLiBOb3cgY2xpY2sgUnVuLg0KDQo8cCBhbGlnbj0iY2VudGVyIj48ZGl2IGNsYXNzPSJ6b29tIj48aW1nIHNyYz0gIkltYWdlcy9xZ2lzLXNwYXRpYWwtam9pbi5wbmciIGFsdD0iU3BhdGlhbCBKb2luIERhdGFzZXRzIERpYWxvZyIgc3R5bGU9IndpZHRoOjEwMCUiPjwvZGl2PjwvcD4NClwqSWYgeW91IGNob29zZSB0byBtYWtlIGEgdGVtcG9yYXJ5IGZpbGUgeW91IHNob3VsZCByZW5hbWUgaXQgaW4gdGhlIGxheWVycyB3aXRoIGEgc2Vuc2libGUgbmFtZS4NCg0KQnkgZXhhbWluaW5nIHRoZSBhdHRyaWJ1dGUgdGFibGUgZm9yIHRoZSBuZXcgZGF0YXNldCB5b3Ugc2hvdWxkIHNlZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgKipOYW1lX2NvdW50KiouIFRoaXMgaXMgdGhlIG51bWJlciBvZiBicm93bmZpZWxkcyB0aGF0IG9jY3VyIHdpdGhpbiBlYWNoIHdhdGVyc2hlZC4gVW5mb3J0dW5hdGVseSwgc29tZSBvZiB0aGUgY2VsbHMgYXJlIHBvcHVsYXRlZCB3aXRoICJOdWxsIiB2YWx1ZXMuIFlvdSBuZWVkIHRvIHJlbW92ZSB0aGVzZSBpbiBvcmRlciB0byBjcmVhdGUgYSBwcm9wZXIgZ3JhZHVhdGVkIGNvbG9yIHNjaGVtZS4gVG8gZG8gdGhpcyB5b3Ugd2lsbCBvcGVuIHRoZSBhdHRyaWJ1dGUgdGFibGUgZm9yIG5ld2x5IGNyZWF0ZWQgZGF0YXNldCBhbmQgY2xpY2sgdGhlIF9GaWVsZCBjYWxjdWxhdG9yXyBidXR0b24gPGltZyBzcmM9ICJJbWFnZXMvcWdpcy1maWVsZC1jYWxjdWxhdG9yLWJ1dHRvbi5qcGciIGFsdD0iRmllbGQgQ2FsY3VsYXRvciBidXR0b24iIHdpZHRoID0gIjIwIiBoZWlnaHQgPSAiMjAiPi4gSW4gdGhlIG5ldyB3aW5kb3cgdW5jaGVjayB0aGUgYm94IGZvciAiQ3JlYXRlIGEgbmV3IGZpZWxkIiBhbmQgY2hlY2sgdGhlIGJveCBmb3IgIlVwZGF0ZSBleGlzdGluZyBmaWVsZCIuIEluIHRoZSBkcm9wLWRvd24gbWVudSBiZWxvdyB0aGUgYm94IHNlbGVjdCBfTmFtZV9jb3VudF8uIEluIHRoZSBFeHByZXNzaW9uIGJveCB0eXBlIHRoZSBmb2xsb3dpbmcgYW5kIGNsaWNrIE9LOg0KDQpgYGBpZigiTmFtZV9jb3VudCIgaXMgbnVsbCwgMCwgIk5hbWVfY291bnQiKWBgYA0KDQo8cCBhbGlnbj0iY2VudGVyIj48ZGl2IGNsYXNzPSJ6b29tIj48aW1nIHNyYz0gIkltYWdlcy9xZ2lzLWZpZWxkLWNhbGN1bGF0b3IucG5nIiBhbHQ9IkZpZWxkIENhbGN1bGF0b3IiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L2Rpdj48L3A+DQoNClRoaXMgd2lsbCByZXBsYWNlIGFsbCBvZiB0aGUgbnVsbCB2YWx1ZXMgd2l0aCB6ZXJvIHZhbHVlcy4gRmluYWxseSwgY2xpY2sgdGhlIF9Ub2dnbGUgZWRpdGluZyBtb2RlXyBidXR0b24gPGltZyBzcmM9ICJJbWFnZXMvcWdpcy1lZGl0b3ItYnV0dG9uLmpwZyIgYWx0PSJ0b2dnbGUgRWRpdGluZyIgd2lkdGggPSAiMjAiIGhlaWdodCA9ICIyMCI+IGFuZCBzYXZlIHRoZSBjaGFuZ2VzIHRvIHRoZSB0YWJsZS4NCg0KTm93LCB1c2luZyB0aGUgc2tpbGxzIHlvdSBsZWFybmVkIGluIEV4ZXJjaXNlcyBbVHdvXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS0yLyksIFtUaHJlZV0oaHR0cHM6Ly9jaHJpc21nZW50cnkuZ2l0aHViLmlvL0dJUzEtRXhlcmNpc2UtMy8pLCBhbmQgW0ZvdXJdKGh0dHBzOi8vY2hyaXNtZ2VudHJ5LmdpdGh1Yi5pby9HSVMxLUV4ZXJjaXNlLTQvKSB5b3UgY2FuIG5vdyBtYWtlIGEgbWFwIHRoYXQgc2hvd3MgTW9udGdvbWVyeSBDb3VudHksIHRoZSBsb2NhdGlvbiBvZiBicm93bmZpZWxkcyBhbmQgd2F0ZXJzaGVkcyBpbiBhIGdyYWR1YXRlZCBjb2xvciBzY2hlbWUgYnkgbnVtYmVyIG9mIGJyb3duZmllbGRzLiBSZW1lbWJlciB0byBpbmNsdWRlIGNhcnRvZ3JhcGhpYyBlbGVtZW50cyBzdWNoIGFzIGxlZ2VuZCwgc2NhbGUgYmFyLCBub3J0aCBhcnJvdywgZXRjLiBJbiB0aGlzIHZpc3VhbGl6YXRpb24geW91IG1heSBhbHNvIHdhbnQgdG8gYWRkIGEgZGlmZmVyZW50IGJhc2VtYXAgb3IgaW5zZXQgbWFwIHRoYXQgcHJvdmlkZXMgYWRkaXRpb25hbCBzdXBwb3J0aW5nIGluZm9ybWF0aW9uLg0KDQo8YmlnPjxiPlF1ZXN0aW9uIE5vLiAzPC9iPjwvYmlnPg0KPGJsb2NrcXVvdGU+DQpXaGljaCB3YXRlcnNoZWQgY29udGFpbnMgdGhlIG1vc3QgYnJvd25maWVsZHM/DQo8L2Jsb2NrcXVvdGU+DQoNCjwvZGV0YWlscz4NCjxocj48L2hyPg0KDQo8ZGV0YWlscz48c3VtbWFyeT48YmlnPlZpZXcgZGlyZWN0aW9ucyBpbiA8Yj4gW1Jde3N0eWxlPSJjb2xvcjojNjQ5NUVEIn0gPC9iPjwvc3Bhbj48L2JpZz48L3N1bW1hcnk+DQoNCkV4YW1pbmUgdGhlIHNwYXRpYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBicm93bmZpZWxkIHRocm91Z2hvdXQgdGhlIGNvdW50eS4gVGhlIGNsdXN0ZXJpbmcgc2hvdWxkIGJlIHJlbGF0aXZlbHkgYXBwYXJlbnQgYW5kIG1pZ2h0IG1hdGNoIHVwIHdpdGggeW91ciBrbm93bGVkZ2Ugb2YgaW5kdXN0cmlhbCBhY3Rpdml0aWVzIGluIHRoZSB2YXJpb3VzIGFyZWFzIG9mIE1vbnRnb21lcnkgQ291bnR5LiBVc2UgdGhlIHNraWxscyB5b3UgZGV2ZWxvcGVkIGluIEV4ZXJjaXNlcyBbNF0oaHR0cHM6Ly9jaHJpc21nZW50cnkuZ2l0aHViLmlvL0dJUzEtRXhlcmNpc2UtNC8jMTNfU3RlcF9UaHJlZTpfVGhlX1Zpc3VhbGl6YXRpb24pLCBbM10oaHR0cHM6Ly9jaHJpc21nZW50cnkuZ2l0aHViLmlvL0dJUzEtRXhlcmNpc2UtMy8jMTNfU3RlcF9UaHJlZTpfVGhlX1Zpc3VhbGl6YXRpb24pLCBhbmQgWzJdKGh0dHBzOi8vY2hyaXNtZ2VudHJ5LmdpdGh1Yi5pby9HSVMxLUV4ZXJjaXNlLTIvKSB0byAqKl9jb21wbGV0ZV8qKiB0aGUgc2NyaXB0cyBiZWxvdyBhbmQgY3JlYXRlIHRoZSB2aXN1YWxpemF0aW9ucyBmb3IgdGhlIG51bWJlciBvZiBicm93bmZpZWxkcyBwZXIgd2F0ZXJzaGVkIGFuZCB0aGUgbnVtYmVyIG9mIGJyb3duZmllbGRzIHBlciBjZW5zdXMgdHJhY3QuIERvbid0IGZvcmdldCB0byBhZGQgYWxsIG9mIHRoZSBuZWNlc3NhcnkgbWFwIGVsZW1lbnRzIGFuZCBmZWVsIGZyZWUgdG8gYWRkIGFueSBhbmNpbGxhcnkgZGF0YSBmcm9tIHRoaXMgb3IgcHJldmlvdXMgZXhlcmNpc2VzIHRoYXQgZW5oYW5jZSB5b3VyIG1hcC4NCg0KV2F0ZXJzaGVkIE1hcDoNCmBgYHtyIHdhdGVyc2hlZCB2aXN1YWxpemF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9DQojZ2dwbG90KCkgKw0KI2dlb21fcG9seWdvbihkYXRhID0gREFUQVNFVCwgYWVzKHg9bG9uZywgeT1sYXQsIGdyb3VwPWdyb3VwLCBmaWxsID0gU0VMRUNUIFRIRSBBUFBST1BSSUFURSBWQVJJQUJMRSksIGNvbG9yID0gImdyYXkiLCBzaXplID0gMC4yNSwgbGluZXR5cGU9ImRhc2hlZCIpICsgDQojZ2VvbV9wb2x5Z29uKGRhdGEgPSBtb250Y28sIGFlcyh4PWxvbmcsIHk9bGF0LCBncm91cD1ncm91cCksIGZpbGwgPSBOQSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMSkgKyANCiNnZW9tX3BvaW50KGRhdGEgPSBEQVRBU0VULCBhZXMoeD1sb25nLCB5PWxhdCksIGNvbG9yID0gIlNFTEVDVCBBIENPTE9SIikgKw0KI2Nvb3JkX2ZpeGVkKCkgKw0KI0FERCBUSEUgTkVDRVNTQVJZIEVMRU1FTlRTIEhFUkUNCmBgYA0KDQpDZW5zdXMgVHJhY3QgTWFwOg0KYGBge3IgY2Vuc3VzIHRyYWN0IHZpc3VhbGl6YXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0NCiNnZ3Bsb3QoKSArDQojZ2VvbV9zZihkYXRhID0gREFUQVNFVCwgYWVzKGZpbGwgPSBTRUxFQ1QgVEhFIEFQUFJPUFJJQVRFIFZBUklBQkxFKSkgKyBzY2FsZV9maWxsX3ZpcmlkaXNfYyhkaXJlY3Rpb24gPSAtMSwgb3B0aW9uID0gIkEiKSArDQojZ2VvbV9wb2ludChkYXRhID0gREFUQVNFVCwgYWVzKHg9bG9uZywgeT1sYXQpLCBjb2xvciA9ICJyZWQiKSArDQojY29vcmRfc2YoKSArDQojQUREIFRIRSBORUNFU1NBUlkgRUxFTUVOVFMgSEVSRQ0KYGBgDQoNClJlbWVtYmVyIHRvIHJlbW92ZSBhbGwgXCMgY29tbWVudCB0YWdzIGJlZm9yZSBydW5uaW5nIHRoZSBlZGl0ZWQgc2NyaXB0cy4NCg0KPGJpZz48Yj5RdWVzdGlvbiBOby4gMzwvYj48L2JpZz4NCjxibG9ja3F1b3RlPg0KV2hpY2ggd2F0ZXJzaGVkIGNvbnRhaW5zIHRoZSBtb3N0IGJyb3duZmllbGRzPw0KPC9ibG9ja3F1b3RlPg0KDQo8L2RldGFpbHM+DQoNCiMjIFN0ZXAgRm91cjogVGhlIENvdW50eSBDb21taXNzb24gUmVwb3J0DQoNCkFmdGVyIGRpc2N1c3NpbmcgdGhlIHJlc3VsdHMgb2YgdGhlIHByZXZpb3VzIGFuYWx5c2lzIHdpdGggeW91ciBjb2xsZWFndWVzIGF0IENvdW50eSBDb21taXNzaW9uLCBTdG9ybXdhdGVyIE1hbmFnZW1lbnQsIEhlYWx0aCBEZXBhcnRtZW50LCBhbmQgVERFQywgdGhleSBhcmUgaW50ZXJlc3RlZCBpbiBzZWVpbmcgaG93IHRoZSBsb2NhdGlvbiBvZiBicm93bmZpZWxkcyBpbXBhY3RzIHRoZSBjb21tdW5pdHkuIEFsdGhvdWdoIHRoZSBbY29tbWlzc2lvbiBkaXN0cmljdHNdKGh0dHBzOi8vbWNndG4ub3JnL3N0b3JhZ2UvZGVwYXJ0bWVudHMvY29tbWlzc2lvbi9tYXBzL0Rpc3RyaWN0TWFwLnBkZikgZG8gbm90IHBlcmZlY3RseSByZXBsaWNhdGUgdGhlIGNlbnN1cyB0cmFjdHMsIHRoZSBDb3VudHkgQ29tbWlzc2lvbmVycyBhbmQgdGhlIEhlYWx0aCBEZXBhcnRtZW50IHdhbnQgdG8ga25vdyBpZiB0aGUgYnJvd25maWVsZCBzaXRlcyBhcmUgZGlyZWN0bHkgcmVsYXRlZCB0byBjZW5zdXMgdHJhY3RzIHdpdGggbGFyZ2UgbWlub3JpdHkgcG9wdWxhdGlvbnMuIFRoZXkgYXJlIGNvbmNlcm5lZCBieSBhIFtyZWNlbnRseSBwdWJsaXNoZWQgcmVwb3J0XShodHRwczovL3d3dy5lcGEuZ292L2NsZWFudXBzL29sZW0tcHJvZ3JhbXMtYWRkcmVzcy1jb250YW1pbmF0aW9uLXN1cGVyZnVuZC1icm93bmZpZWxkcy1hbmQtcmNyYS1zaXRlcy1uZWFyLTYwLXBlcmNlbnQtdXMpIHRoYXQgc3RhdGVzOg0KDQo+ICJXaGlsZSB0aGVyZSBpcyBubyBzaW5nbGUgd2F5IHRvIGNoYXJhY3Rlcml6ZSBjb21tdW5pdGllcyBsb2NhdGVkIG5lYXIgb3VyIHNpdGVzLCB0aGlzIHBvcHVsYXRpb24gaXMgbW9yZSBtaW5vcml0eSwgbG93IGluY29tZSwgbGluZ3Vpc3RpY2FsbHkgaXNvbGF0ZWQsIGFuZCBsZXNzIGxpa2VseSB0byBoYXZlIGEgaGlnaCBzY2hvb2wgZWR1Y2F0aW9uIHRoYW4gdGhlIFUuUy4gcG9wdWxhdGlvbiBhcyBhIHdob2xlLiBBcyBhIHJlc3VsdCwgdGhlc2UgY29tbXVuaXRpZXMgbWF5IGhhdmUgZmV3ZXIgcmVzb3VyY2VzIHdpdGggd2hpY2ggdG8gYWRkcmVzcyBjb25jZXJucyBhYm91dCB0aGVpciBoZWFsdGggYW5kIGVudmlyb25tZW50LiINCg0KRHVyaW5nIHRoZXNlIGRpc2N1c3Npb25zIHRoZSBIZWFsdGggRGVwYXJ0bWVudCB3b3VsZCBhbHNvIGxpa2UgdG8ga25vdyBpZiB0aGUgYXJlYXMgd2l0aCBhIGhpZ2ggbnVtYmVyIG9mIGJyb3duZmllbGRzIGhhdmUgaGlnaGVyIHBvcHVsYXRpb25zIG9mIGNoaWxkcmVuLg0KDQoNCjxkZXRhaWxzPjxzdW1tYXJ5PjxiaWc+VmlldyBkaXJlY3Rpb25zIGluIDxiPiBbQXJjR0lTIFByb117c3R5bGU9ImNvbG9yOiNmZjQ1MDAifSA8L2I+PC9zcGFuPjwvYmlnPjwvc3VtbWFyeT4NCg0KVXNpbmcgdGhlIHNraWxscyB5b3UgbGVhcm5lZCBpbiB0aGlzIGFuZCBwcmV2aW91cyBleGVyY2lzZXMsIGNyZWF0ZSBhIG5ldyBfc3BhdGlhbCBqb2luXyBiZXR3ZWVuIHRoZSBfY2Vuc3VzIHRyYWN0c18gYW5kIF9icm93bmZpZWxkc18gZGF0YXNldHMgKGZvciB0aGlzIGV4ZXJjaXNlIGlnbm9yZSBhbnkgZGF0dW0gd2FybmluZykuIEFzIHdpdGggdGhlIHByZXZpb3VzIHNwYXRpYWwgam9pbiwgeW91IHNob3VsZCBub3cgaGF2ZSBhbiBhZGRpdGlvbmFsIHZhcmlhYmxlIGxhYmVsZWQgIkpvaW5fQ291bnQiIHRoYXQgZGV0YWlscyB0aGUgbnVtYmVyIG9mIGJyb3duZmllbGRzIHBlciBjZW5zdXMgdHJhY3QuDQoNCk9uZSB3YXkgeW91IGNhbiB2aWV3IHR3byB2YXJpYWJsZXMgYXQgb25jZSBvbiBhIG1hcCBpcyB0byBjcmVhdGUgYml2YXJpYXRlIHN5bWJvbG9neS4NCg0KPHAgYWxpZ249ImNlbnRlciI+PGltZyBzcmM9ICJJbWFnZXMvc3ltYm9sb2d5LWJpdmFyaWF0ZS1wYW5lLmpwZyIgYWx0PSJCaXZhcmlhdGUgQ29sb3IgU2VsZWN0aW9uIiBzdHlsZT0id2lkdGg6NjUlIj48L3A+DQoNClRoaXMgY3JlYXRlcyBhIGdyaWQgb2YgY29sb3JzIHdpdGggYW4gWCBhbmQgWSBheGlzIHdpdGggdGhlIGZvbGxvd2luZyBjYXRlZ29yaWVzOg0KDQo8cCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0gIkltYWdlcy9iaXZhcmlhdGUtY29sb3Itc2NoZW1lLnBuZyIgYWx0PSJCaXZhcmlhdGUgQ29sb3IgU2NoZW1lIiBzdHlsZT0id2lkdGg6NjUlIj48L3A+DQoNCi0gV2hlcmUgdGhlIEJvdHRvbSBMZWZ0IGNlbGwgaW5kaWNhdGVzIGxvdyB2YWx1ZXMgaW4gYm90aCB2YXJpYWJsZXMNCi0gV2hlcmUgdGhlIFVwcGVyIExlZnQgY2VsbCBpbmRpY2F0ZXMgaGlnaCB2YWx1ZXMgaW4gdGhlIGZpcnN0IHZhcmlhYmxlIGFuZCBsb3cgdmFsdWVzIGluIHRoZSBzZWNvbmQgdmFyaWFibGUNCi0gV2hlcmUgdGhlIEJvdHRvbSBSaWdodCBjZWxsIGluZGljYXRlcyBsb3cgdmFsdWVzIGluIHRoZSBmaXJzdCB2YXJpYWJsZSBhbmQgaGlnaCB2YWx1ZXMgaW4gdGhlIHNlY29uZCB2YXJpYWJsZQ0KLSBXaGVyZSB0aGUgVXBwZXIgUmlnaHQgY2VsbCBpbmRpY2F0ZXMgaGlnaCB2YWx1ZXMgaW4gdGhlIGZpcnN0IHZhcmlhYmxlIGFuZCBoaWdoIHZhbHVlcyBpbiB0aGUgc2Vjb25kIHZhcmlhYmxlDQoNClRoZSBvdGhlciBncmlkIGNlbGxzIHJlcHJlc2VudCBtaWRwb2ludHMgaW4gdGhlIHZhcmlhYmxlcy4gVGhlIHZhcmlhYmxlcyBjYW4gYmUgc2VsZWN0ZWQgaW4gdGhlIF9zeW1ib2xvZ3kgcGFuZV8gd2hlcmUgIkZpZWxkIDEiIGlzIG9uZSB2YXJpYWJsZSBhbmQgIkZpZWxkIDIiIGlzIHRoZSBvdGhlciB2YXJpYWJsZS4gU28gdG8gdmlzdWFsaXplIF9icm93bmZpZWxkc18gYW5kIG9uZSBvZiB0aGUgcG9wdWxhdGlvbiBkZW1vZ3JhcGhpY3Mgc2VsZWN0IG9uZSBmb3IgZWFjaCBmaWVsZC4gRm9yICJHcmlkIFNpemUiIHNlbGVjdCAzeDMuIFlvdSBjYW4gc2VsZWN0IHlvdXIgb3duIGNvbG9yIHNjaGVtZSB3aXRoIHRoZSBkcm9wLWRvd24gbWVudS4gSW4gdGhlIGZpZWxkcyBzZWN0aW9uIGJlbG93LCB5b3UgY2FuIHJlbmFtZSB0aGUgZmllbGRzIChlLmcuICJqb2luIGNvdW50IiBtZWFucyBub3RoaW5nIHNvIGdpdmUgaXQgYW4gYXBwcm9wcmlhdGUgbmFtZSkuDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxpbWcgc3JjPSAiSW1hZ2VzL2FyY2dpcy1iaXZhcmlhdGUtb3B0aW9ucy5wbmciIGFsdD0iQml2YXJpYXRlIENvbG9yIE9wdGlvbnMiIHN0eWxlPSJ3aWR0aDo2NSUiPjwvcD4NCg0KV2l0aCB0aGVzZSBzZXR0aW5ncyB5b3Ugc2hvdWxkIGhhdmUgYSBzeW1ib2xvZ3kgdGhhdCBzaG93cyBpZiBhIGNlbnN1cyB0cmFjdCBpcyBoaWdoIG9yIGxvdyBpbiBlaXRoZXIgb2YgdGhlIHBhcnRpY3VsYXIgdmFyaWFibGVzLiBUZXN0IGEgbnVtYmVyIG9mIGRpZmZlcmVudCB2YXJpYWJsZSBjb21iaW5hdGlvbnMgd2l0aCB0aGUgY291bnQgb2YgYnJvd25maWVsZHMgYW5kIHZhcmlvdXMgZGVtb2dyYXBoaWMgY2F0ZWdvcmllcy4gDQoNCjxiaWc+PGI+UXVlc3Rpb24gTm8uIDQ8L2I+PC9iaWc+DQo8YmxvY2txdW90ZT4NCldoaWNoIGNlbnN1cyB0cmFjdCBjb250YWlucyB0aGUgbW9zdCBicm93bmZpZWxkcz8NCjwvYmxvY2txdW90ZT4NCg0KPC9kZXRhaWxzPg0KPGhyPjwvaHI+DQoNCjxkZXRhaWxzPjxzdW1tYXJ5PjxiaWc+VmlldyBkaXJlY3Rpb25zIGluIDxiPiBbUUdJU117c3R5bGU9ImNvbG9yOiMwMDY0MDAifSA8L2I+PC9zcGFuPjwvYmlnPjwvc3VtbWFyeT4NCg0KVXNpbmcgdGhlIHNraWxscyB5b3UgbGVhcm5lZCBpbiB0aGlzIGFuZCBwcmV2aW91cyBleGVyY2lzZXMsIGNyZWF0ZSBhIG5ldyBfSm9pbiBhdHRyaWJ1dGVzIGJ5IGxvY2F0aW9uIChTdW1tYXJ5KV8gYmV0d2VlbiB0aGUgX2NlbnN1c190cmFjdHNfIGFuZCBfYnJvd25maWVsZHNfIGRhdGFzZXRzIChmb3IgdGhpcyBleGVyY2lzZSBpZ25vcmUgYW55IGRhdHVtIHdhcm5pbmcpLiBBcyB3aXRoIHRoZSBwcmV2aW91cyBzcGF0aWFsIGpvaW4sIHlvdSBzaG91bGQgbm93IGhhdmUgYW4gYWRkaXRpb25hbCB2YXJpYWJsZSBsYWJlbGVkICJOYW1lX2NvdW50IiB0aGF0IGRldGFpbHMgdGhlIG51bWJlciBvZiBicm93bmZpZWxkcyBwZXIgY2Vuc3VzIHRyYWN0Lg0KDQpPbmUgd2F5IHlvdSBjYW4gdmlldyB0d28gdmFyaWFibGVzIGF0IG9uY2Ugb24gYSBtYXAgaXMgdG8gY3JlYXRlIGJpdmFyaWF0ZSBzeW1ib2xvZ3kuIFRoaXMgY3JlYXRlcyBhIGdyaWQgb2YgY29sb3JzIHdpdGggYW4gWCBhbmQgWSBheGlzIHdpdGggdGhlIGZvbGxvd2luZyBjYXRlZ29yaWVzOg0KDQo8cCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0gIkltYWdlcy9iaXZhcmlhdGUtY29sb3Itc2NoZW1lLnBuZyIgYWx0PSJCaXZhcmlhdGUgQ29sb3IgU2NoZW1lIiBzdHlsZT0id2lkdGg6NjUlIj48L3A+DQoNCi0gV2hlcmUgdGhlIEJvdHRvbSBMZWZ0IGNlbGwgaW5kaWNhdGVzIGxvdyB2YWx1ZXMgaW4gYm90aCB2YXJpYWJsZXMNCi0gV2hlcmUgdGhlIFVwcGVyIExlZnQgY2VsbCBpbmRpY2F0ZXMgaGlnaCB2YWx1ZXMgaW4gdGhlIGZpcnN0IHZhcmlhYmxlIGFuZCBsb3cgdmFsdWVzIGluIHRoZSBzZWNvbmQgdmFyaWFibGUNCi0gV2hlcmUgdGhlIEJvdHRvbSBSaWdodCBjZWxsIGluZGljYXRlcyBsb3cgdmFsdWVzIGluIHRoZSBmaXJzdCB2YXJpYWJsZSBhbmQgaGlnaCB2YWx1ZXMgaW4gdGhlIHNlY29uZCB2YXJpYWJsZQ0KLSBXaGVyZSB0aGUgVXBwZXIgUmlnaHQgY2VsbCBpbmRpY2F0ZXMgaGlnaCB2YWx1ZXMgaW4gdGhlIGZpcnN0IHZhcmlhYmxlIGFuZCBoaWdoIHZhbHVlcyBpbiB0aGUgc2Vjb25kIHZhcmlhYmxlDQoNClRoZSBvdGhlciBncmlkIGNlbGxzIHJlcHJlc2VudCBtaWRwb2ludHMgaW4gdGhlIHZhcmlhYmxlcy4gWW91IGNhbiBjcmVhdGUgdGhlc2UgYml2YXJpYXRlIG1hcHMgaW4gUUdJUyB3aXRoIHNvbWUgZWRpdGluZyBvZiB0aGUgaW5kaXZpZHVhbCBjb2xvciBwYWxldHRlcyBpbiB5b3VyIGdyYWR1YXRlIGNvbG9ycyBtYXAgYW5kIGJ5IHVzaW5nIGEgcGx1Zy1pbiB0byBjcmVhdGUgdGhlIGxlZ2VuZC4gSW4gb3JkZXIgdG8gY3JlYXRlIHRoZSBtYXAgeW91IGZpcnN0IG5lZWQgdG8gZHVwbGljYXRlIHlvdXIgbGF5ZXIuIFRoaXMgZXhhbXBsZSB3aWxsIHVzZSB0aGUgX2NlbnN1cyB0cmFjdF8gZGF0YXNldCB3aXRoIHRoZSAiTmFtZV9jb3VudCIgdmFyaWFibGUgZm9yIG51bWJlciBvZiBicm93bmZpZWxkcyBhbmQgdmFyaWFibGVzIGZvciBkaWZmZXJlbnQgZGVtb2dyYXBoaWNzIHN1Y2ggYXMgdG90YWwgcG9wdWxhdGlvbiAodG90X3BvcCkuIFRvIGR1cGxpY2F0ZSBhIGxheWVyLCByaWdodC9DUlRMIGNsaWNrIG9uIGEgbGF5ZXIgYW5kIHNlbGVjdCAqKkR1cGxpY2F0ZSBMYXllcioqLiBJZiBpdCBoZWxwcyB5b3UgdG8ga2VlcCB0aGUgdHdvIGxheWVycyBvcmdhbml6ZWQsIHlvdSBjYW4gYW1lbmQgdGhlaXIgbGF5ZXIgbmFtZSB0byBpbmNsdWRlIHRoZSB2YXJpYWJsZSB1c2VkIGZvciB0aGUgZ3JhZHVhdGVkIGNvbG9ycyAoZS5nLiB0cmFjdHNfYnJvd25maWVsZHNfY291bnQgb3IgdHJhY3RzX2Jyb3duZmllbGRzX3BvcCkuIE90aGVyd2lzZSBqdXN0IHJlbWVtYmVyIHdoYXQgZWFjaCBvbmUgaXMgZGlzcGxheWluZy4NCg0KTmV4dCwgeW91IHdpbGwgbmVlZCB0byBjcmVhdGUgYSBncmFkdWF0ZWQgc3ltYm9sb2d5IGZvciBlYWNoIGxheWVyIHdpdGggdGhyZWUgKDMpIGNhdGVnb3JpZXMgYW5kIGEgc3BlY2lmaWMgY29sb3IgcGFsZXR0ZS4gQmVjYXVzZSBiaXZhcmlhdGUgbWFwcyBibGVuZCB0d28gY29sb3Igc2NoZW1lcyBpdCBpcyBpbXBvcnRhbnQgdG8gaGF2ZSB0aGUgYXBwcm9wcmlhdGUgY29sb3Igc2VsZWN0aW9uLiBIZXJlIGlzIGFuIGV4YW1wbGUgb2Ygc2V2ZXJhbCBiaXZhcmlhdGUgY29sb3IgcGFsZXR0ZXMgZnJvbSBbSm9zaHVhIFN0ZXZlbnNdKGh0dHBzOi8vd3d3Lmpvc2h1YXN0ZXZlbnMubmV0L2NhcnRvZ3JhcGh5L21ha2UtYS1iaXZhcmlhdGUtY2hvcm9wbGV0aC1tYXAvKQ0KDQo8cCBhbGlnbj0iY2VudGVyIj48ZGl2IGNsYXNzPSJ6b29tIj48aW1nIHNyYz0gIkltYWdlcy9iaXZhcmlhdGUtY29sb3ItcGFsZXR0ZXMucG5nIiBhbHQ9IkJpdmFyaWF0ZSBDb2xvciBQYWxldHRlcyIgc3R5bGU9IndpZHRoOjEwMCUiPjwvZGl2PjwvcD4NCg0KVGhpcyBleGFtcGxlIHdpbGwgdXNlIHRoZSBzZWNvbmQgY29sb3IgcGFsZXR0ZS4gVGhlcmUgYXJlIGEgZmV3IHN0ZXBzIHJlcXVpcmVkIHRvIG1hdGNoIHlvdXIgZ3JhZHVhdGVkIGNvbG9ycyBjYXRlZ29yaWVzIHRvIHRoZSBjb2xvciBwYWxldHRlcyBvbiB0aGUgWCBhbmQgWSBheGVzIGluIHRoZSBpbWFnZSBhYm92ZToNCg0KICAxLiBTZWxlY3QgdGhlIGFwcHJvcHJpYXRlIF92YWx1ZV8uIFRvdF9Qb3AgYW5kIE5hbWVfQ291bnQgd2lsbCBiZSB1c2VkIGZvciB0aGlzIGV4YW1wbGUuDQogIDIuIFNldCB0aGUgY2xhc3NlcyB0byAzLg0KICAzLiBEb3VibGUtY2xpY2sgb24gdGhlIGZpcnN0IG9mIHRoZSBzZWxlY3RlZCBjb2xvcnMuDQogIDQuIEluIHRoZSBuZXcgX1N5bWJvbCBTZWxlY3Rvcl8gd2luZG93LCBjbGljayBvbiB0aGUgY29sb3IgYmFyLg0KICA1LiBJbiB0aGUgbmV4dCBfU2VsZWN0IENvbG9yXyB3aW5kb3csIHR5cGUgaW4gdGhlIEhUTUwgbm90YXRpb24gdGhhdCBtYXRjaGVzIHlvdXIgc2VsZWN0ZWQgcGFsZXR0ZS4gUmVtZW1iZXIsIG9uZSBvZiB5b3VyIGxheWVycyB3aWxsIHN0YXJ0IGF0IHRoZSBib3R0b20gbGVmdCBhbmQgd29yayB1cCBhbmQgdGhlIG90aGVyIHdpbGwgc3RhcnQgYW5kIHRoZSBib3R0b20gbGVmdCBhbmQgd29yayB0byB0aGUgcmlnaHQuDQoNCkZpbmFsbHksIGNsaWNrIE9LIG9uIHRoZSB3aW5kb3dzIGluIFN0ZXBzIDMgYW5kIDQgYW5kIHJlcGVhdCB0aGUgcHJvY2VzcyBmb3IgdGhlIG5leHQgY29sb3IgbW92aW5nIHByb2dyZXNzaXZlbHkgdXAgb3IgcmlnaHQgb24gdGhlIHNlbGVjdGVkIGJpdmFyaWF0ZSBwYWxldHRlIGRlcGVuZGluZyBvbiB0aGUgbGF5ZXIuIFRoaXMgcHJvY2VzcyB3aWxsIG5lZWQgdG8gYmUgY29tcGxldGVkIGZvciBib3RoIG9mIHRoZSBsYXllcnMgKG9uZSB3aXRoIHRoZSBicm93bmZpZWxkIGNvdW50IGFuZCB0aGUgb3RoZXIgd2l0aCBhIGRlbW9ncmFwaGljIHZhcmlhYmxlKSB5b3Ugd2lsbCB1c2UgaW4geW91ciBiaXZhcmlhdGUgbWFwLg0KDQo8cCBhbGlnbj0iY2VudGVyIj48ZGl2IGNsYXNzPSJ6b29tIj48aW1nIHNyYz0gIkltYWdlcy9xZ2lzLWN1c3RvbWl6ZS1jb2xvci1zdGVwcy5wbmciIGFsdD0iQml2YXJpYXRlIENvbG9yIFBhbGV0dGUgU3RlcHMiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L2Rpdj48L3A+DQoNCk9uY2UgeW91IGhhdmUgY29tcGxldGVkIHRoaXMgcHJvY2VzcyBmb3IgZWFjaCBvZiB0aGUgbGF5ZXJzIHlvdSBzaG91bGQgcmV0dXJuIHRvIHRoZSBwcm9wZXJ0aWVzIG1lbnUgb2YgdGhlIGZpcnN0IGxheWVyIGFuZCB1bmRlciB0aGUgX1N5bWJvbG9neV8gdGFiIHNjcm9sbCBkb3duIHRvIF9MYXllciBSZW5kZXJpbmdfIGFuZCBleHBhbmQgdGhlIG9wdGlvbnMgdG8gc2VlIHRoZSBvcHRpb25zIGZvciAqKkJsZW5kaW5nIG1vZGUqKi4gQ2hvb3NlIF9tdWx0aXBseV8gZm9yIHRoZSBsYXllciwgYW5kIF9ub3JtYWxfIGZvciB0aGUgZmVhdHVyZSBhbmQgY2xpY2sgT0suDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxkaXYgY2xhc3M9Inpvb20iPjxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtbGF5ZXItcmVuZGVyaW5nLmpwZyIgYWx0PSJMYXllciBSZW5kZXJpbmciIHN0eWxlPSJ3aWR0aDoxMDAlIj48L2Rpdj48L3A+DQoNCldpdGggYm90aCBsYXllcnMgdmlld2FibGUgeW91IHNob3VsZCBub3cgaGF2ZSBhIGJpdmFyaWF0ZSBjb2xvciBwYWxldHRlIGZvciB0aGUgZGF0YS4NCg0KPHAgYWxpZ249ImNlbnRlciI+PGRpdiBjbGFzcz0iem9vbSI+PGltZyBzcmM9ICJJbWFnZXMvcWdpcy1iaXZhcmlhdGUtbWFwLnBuZyIgYWx0PSJCaXZhcmlhdGUgTWFwIiBzdHlsZT0id2lkdGg6MTAwJSI+PC9kaXY+PC9wPg0KDQpCZWNhdXNlIFFHSVMgaXMgdW5hYmxlIHRvIGludGVycHJldCB0aGUgYXBwcm9wcmlhdGUgbGVnZW5kIHN0eWxlIGZyb20gdGhlIGF2YWlsYWJsZSBkYXRhIHlvdSBuZWVkIHRvIGFkZCBhIHBsdWctaW4uIENsaWNrICoqUGx1Z2lucyA+IE1hbmFnZSBhbmQgSW5zdGFsbCBQbHVnaW5zKiogZnJvbSB0aGUgbWVudSBiYXIuIA0KDQo8cCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0gIkltYWdlcy9xZ2lzLW1hbmFnZS1wbHVnaW5zLnBuZyIgYWx0PSJJbnN0YWxsIGFuZCBNYW5hZ2UgUGx1Z2lucyIgc3R5bGU9IndpZHRoOjEwMCUiPjwvcD4NCg0KTmV4dCwgc2VhcmNoIGZvciAiQml2YXJpYXRlIExlZ2VuZCIgaW4gdGhlIHNlYXJjaCBiYXIuIEJlIHN1cmUgX0FsbF8gaXMgc2VsZWN0ZWQgaW4gdGhlIGxlZnQgc2lkZSBjb2x1bW4uIFRoaXMgc2hvdWxkIGJyaW5nIHVwIHRoZSAqQml2YXJpYXRlIExlZ2VuZCogcGx1Z2luLiBDbGljayBfSW5zdGFsbCBQbHVnaW5fIGluIHRoZSBsb3dlciByaWdodCBvZiB0aGUgd2luZG93IHRvIGluc3RhbGwgdGhlIGxlZ2VuZCBnZW5lcmF0b3IuDQoNCjxwIGFsaWduPSJjZW50ZXIiPjxkaXYgY2xhc3M9Inpvb20iPjxpbWcgc3JjPSAiSW1hZ2VzL3FnaXMtYml2YXJpYXRlLWxlZ2VuZC1wbHVnaW4ucG5nIiBhbHQ9Ikluc3RhbGwgQml2YXJpYXRlIExlZ2VuZCBQbHVnaW4iIHN0eWxlPSJ3aWR0aDoxMDAlIj48L2Rpdj48L3A+DQoNCldpdGggdGhlIHBsdWdpbiBpbnN0YWxsZWQgeW91IGNhbiByZXR1cm4gdG8geW91ciBwcm9qZWN0LiBZb3Ugd2lsbCBub3cgaGF2ZSBhIF9CaXZhcmlhdGUgTGVnZW5kXyBidXR0b24gPGltZyBzcmM9ICJJbWFnZXMvcWdpcy1iaXZhcmlhdGUtcGx1Z2luLWJ1dHRvbi5qcGciIGFsdD0iQml2YXJpYXRlIExlZ2VuZCBidXR0b24iIHdpZHRoID0gIjIwIiBoZWlnaHQgPSAiMjAiPiBvbiB5b3VyIHRvb2xiYXIuIENsaWNrIHRoZSBidXR0b24gdG8gb3BlbiB0aGUgbGVnZW5kIGdlbmVyYXRvci4gU2VsZWN0IHRoZSBhcHByb3ByaWF0ZSBfVG9wIGxheWVyXyBmcm9tIHRoZSBkcm9wLWRvd24gbWVudSBhbmQgY2xpY2sgdGhlIGJveCBmb3IgUmV2ZXJzZSBjb2xvcnMuIFNlbGVjdCB0aGUgYXBwcm9wcmlhdGUgX0JvdHRvbSBsYXllcl8sIHNldCB0aGUgX1NxdWFyZSB3aWR0aF8gdG8gNDgsIGFuZCBjaG9vc2UgX011bHRpcGx5XyBmb3IgdGhlIGRyb3AtZG93biBtZW51IGJlbG93LiBUaGVuIGNsaWNrIF9HZW5lcmF0ZSBsZWdlbmRfLg0KDQo8cCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0gIkltYWdlcy9xZ2lzLWJpdmFyaWF0ZS1sZWdlbmQtZ2VuZXJhdG9yLnBuZyIgYWx0PSJCaXZhcmlhdGUgTGVnZW5kIEdlbmVyYXRvciIgc3R5bGU9IndpZHRoOjg1JSI+PC9wPg0KDQpGaW5hbGx5LCBjbGljayAqKkV4cG9ydCBsZWdlbmQgdG8gaW1hZ2UqKiBhbmQgc2F2ZSBpdCBpbiB5b3VyIHByb2plY3QgZm9sZGVyIHdpdGggYSAqKi5wbmcqKiBleHRlbnNpb24uIEluIHlvdXIgbGF5b3V0LCB1c2UgdGhlIF9BZGQgaW1hZ2VfIGJ1dHRvbiA8aW1nIHNyYz0gIkltYWdlcy9xZ2lzLWFkZC1pbWFnZS1idXR0b24tbGF5b3V0LmpwZyIgYWx0PSJBZGQgaW1hZ2UgdG8gbGF5b3V0IGJ1dHRvbiIgd2lkdGggPSAiMjAiIGhlaWdodCA9ICIyMCI+IGFuZCBkcmF3IHRoZSBpbWFnZSBib3ggd2hpbGUgaG9sZGluZyB0aGUgc2hpZnQga2V5IHRvIGNvbnN0cmFpbiB0aGUgYm94IHRvIGEgcGVyZmVjdCBzcXVhcmUuIE5leHQsIHJpZ2h0LWNsaWNrIGluIHRoZSBib3ggYW5kIGdvIHRvIF9JdGVtIHByb3BlcnRpZXNfIHRvIGxvY2F0ZSB0aGUgaW1hZ2UgZmlsZS4gSW4gdGhlIHByb3BlcnRpZXMgcGFuZSwgc2VsZWN0IF9SYXN0ZXIgSW1hZ2VfIGFuZCBuYXZpZ2F0ZSB0byB5b3VyIHByb2plY3QgZm9sZGVyIHRvIGFkZCB0aGUgaW1hZ2UuIA0KDQo8cCBhbGlnbj0iY2VudGVyIj48ZGl2IGNsYXNzPSJ6b29tIj48aW1nIHNyYz0gIkltYWdlcy9xZ2lzLWluc2VydC1pbWFnZS1sZWdlbmQucG5nIiBhbHQ9Ikluc2VydCBMZWdlbmQgSW1hZ2UiIHN0eWxlPSJ3aWR0aDoxMDAlIj48L2Rpdj48L3A+DQoNClJlbWVtYmVyIHRoYXQgdGhpcyBpcyBub3cgc2ltcGx5IGFuIGltYWdlIHdoaWNoIG1lYW5zIHlvdSB3aWxsIG5lZWQgdG8gbWFudWFsbHkgY3JlYXRlIHRoZSBsZWdlbmQgdXNpbmcgdGhlIGltYWdlIGFuZCBpbnNlcnRlZCB0ZXh0LiBCZSBzdXJlIHlvdSByZW1lbWJlciB3aGljaCBkYXRhIGJlbG9uZ3Mgb24gd2hpY2ggYXhpcyBhbmQgdGhpbmsgYWJvdXQgaG93IHlvdSB3YW50IHRoZSByZWFkZXIgdG8gaW50ZXJwcmV0IHRoZSBpbmZvcm1hdGlvbi4gSGVyZSBpcyBhbiBleGFtcGxlIG9mIG9uZSB0aGF0IGNvdWxkIGJlIHVzZWQgZm9yIHRoZSBsZWdlbmQgY3JlYXRlZCBhYm92ZS4NCg0KPHAgYWxpZ249ImNlbnRlciI+PGltZyBzcmM9ICJJbWFnZXMvcWdpcy1zYW1wbGUgYml2YXJpYXRlLWxlZ2VuZC5wbmciIGFsdD0iQml2YXJpYXRlIExlZ2VuZCBFeGFtcGxlIiBzdHlsZT0id2lkdGg6NTAlIj48L3A+DQoNCllvdSBzaG91bGQgPHU+ZXhwZXJpbWVudCB3aXRoIGRpZmZlcmVudCBkZW1vZ3JhcGhpY3M8L3U+IHRvIHNlZSBob3cgdGhleSByZWxhdGUgdG8gdGhlIG51bWJlciBvZiBicm93bmZpZWxkcyBiZWZvcmUgY29tcGxldGluZyB0aGUgYXNzaWdubWVudC4gWW91IHdpbGwgd2FudCB0byBzZWxlY3QgdGhlIHZhcmlhYmxlIHRoYXQgeW91IGJlbGlldmUgc2hvd3Mgd2hpY2ggZGVtb2dyYXBoaWMgd291bGQgbW9zdCBiZSBpbXBhY3RlZCBieSB0aGUgcHJlc2VuY2Ugb2YgYnJvd25maWVsZHMgaW4gdGhlIHZhcmlvdXMgdHJhY3RzLg0KDQo8YmlnPjxiPlF1ZXN0aW9uIE5vLiA0PC9iPjwvYmlnPg0KPGJsb2NrcXVvdGU+DQpXaGljaCBjZW5zdXMgdHJhY3QgY29udGFpbnMgdGhlIG1vc3QgYnJvd25maWVsZHM/DQo8L2Jsb2NrcXVvdGU+DQoNCjwvZGV0YWlscz4NCjxocj48L2hyPg0KDQo8ZGV0YWlscz48c3VtbWFyeT48YmlnPlZpZXcgZGlyZWN0aW9ucyBpbiA8Yj4gW1Jde3N0eWxlPSJjb2xvcjojNjQ5NUVEIn0gPC9iPjwvc3Bhbj48L2JpZz48L3N1bW1hcnk+DQoNCkFzIHN0YXRlZCBhYm92ZSwgdGhlIENvdW50eSBDb21taXNzaW9uZXJzIGFuZCB0aGUgSGVhbHRoIERlcGFydG1lbnQgd2FudCB0byBzZWUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNlbnN1cyB0cmFjdHMgd2l0aCBsYXJnZSBtaW5vcml0eSBwb3B1bGF0aW9ucyBhbmQgYnJvd25maWVsZHMgYW5kIHRoZSBIZWFsdGggRGVwYXJ0bWVudCB3b3VsZCBhbHNvIGxpa2UgdG8gc2VlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBicm93bmZpZWxkcyBqdXZlbmlsZSBwb3B1bGF0aW9ucy4gVGhlIHZpc3VhbGl6YXRpb25zIHlvdSBjcmVhdGVkIGFib3ZlIHNpbXBseSBzaG93IHRoZSBudW1iZXIgb2YgYnJvd25maWVsZHMgcGVyIHdhdGVyc2hlZC9jZW5zdXMgdHJhY3QuIFlvdSBjb3VsZCBjcmVhdGUgYSBxdWFsaXRhdGl2ZSB2aXN1YWxpemF0aW9uIHdoZXJlIGRlbW9ncmFwaGljcyAoZWl0aGVyIG1pbm9yaXR5IGNsYXNzIG9yIGFnZSBjbGFzcykgaXMgdXNlZCBhcyB0aGUgZmlsbCB3aXRoIGJyb3duZmllbGQgbG9jYXRpb25zIGFzIGFuIG92ZXJsYXkuIEhvd2V2ZXIsIHlvdSBjYW4gYWxzbyBjcmVhdGUgYSB0d28gdmFyaWFibGUgcXVhbnRpdGF0aXZlIG1hcCBjYWxsZWQgYSBiaXZhcmlhdGUgbWFwIHRoYXQgZGlzcGxheXMgcXVhbnRpdGF0aXZlIGNhdGVnb3JpZXMgZm9yIHR3byBkaWZmZXJlbnQgdmFyaWFibGVzLiBUaGlzIGNyZWF0ZXMgYSBncmlkIG9mIGNvbG9ycyB3aXRoIGFuIFggYW5kIFkgYXhpcyB3aXRoIHRoZSBmb2xsb3dpbmcgY2F0ZWdvcmllczoNCg0KPHAgYWxpZ249ImNlbnRlciI+PGltZyBzcmM9ICJJbWFnZXMvYml2YXJpYXRlLWNvbG9yLXNjaGVtZS5wbmciIGFsdD0iQml2YXJpYXRlIENvbG9yIFNjaGVtZSIgc3R5bGU9IndpZHRoOjY1JSI+PC9wPg0KDQotIFdoZXJlIHRoZSBCb3R0b20gTGVmdCBjZWxsIGluZGljYXRlcyBsb3cgdmFsdWVzIGluIGJvdGggdmFyaWFibGVzDQotIFdoZXJlIHRoZSBVcHBlciBMZWZ0IGNlbGwgaW5kaWNhdGVzIGhpZ2ggdmFsdWVzIGluIHRoZSBmaXJzdCB2YXJpYWJsZSBhbmQgbG93IHZhbHVlcyBpbiB0aGUgc2Vjb25kIHZhcmlhYmxlDQotIFdoZXJlIHRoZSBCb3R0b20gUmlnaHQgY2VsbCBpbmRpY2F0ZXMgbG93IHZhbHVlcyBpbiB0aGUgZmlyc3QgdmFyaWFibGUgYW5kIGhpZ2ggdmFsdWVzIGluIHRoZSBzZWNvbmQgdmFyaWFibGUNCi0gV2hlcmUgdGhlIFVwcGVyIFJpZ2h0IGNlbGwgaW5kaWNhdGVzIGhpZ2ggdmFsdWVzIGluIHRoZSBmaXJzdCB2YXJpYWJsZSBhbmQgaGlnaCB2YWx1ZXMgaW4gdGhlIHNlY29uZCB2YXJpYWJsZQ0KDQpUaGUgb3RoZXIgZ3JpZCBjZWxscyByZXByZXNlbnQgbWlkcG9pbnRzIGluIHRoZSB2YXJpYWJsZXMuIFlvdSBjYW4gY3JlYXRlIHRoZXNlIGJpdmFyaWF0ZSBtYXBzIGluIFtSXXtzdHlsZT0iY29sb3I6IzY0OTVFRCJ9IG1hbnVhbGx5IG9yIGJ5IHVzaW5nIHRoZSBgYmlzY2FsZWAgcGFja2FnZSBsb2FkZWQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGlzIGV4ZXJjaXNlLiBCZWNhdXNlIGJpdmFyaWF0ZSBtYXBzIGJsZW5kIHR3byBjb2xvciBzY2hlbWVzIGl0IGlzIGltcG9ydGFudCB0byBoYXZlIHRoZSBhcHByb3ByaWF0ZSBjb2xvciBzZWxlY3Rpb24uIFtHcmFkdWF0ZWQgc3ltYm9sb2d5IHBhbGV0dGVzXShodHRwczovL3NsdS1vcGVuZ2lzLmdpdGh1Yi5pby9iaXNjYWxlL3JlZmVyZW5jZS9iaV9wYWwuaHRtbCkgaGF2ZSBiZWVuIGNyZWF0ZWQgdGhhdCBjb3ZlciBhIHJhbmdlIG9mIGNvbG9yIHBvc3NpYmlsaXRpZXMgZm9yIHRoZSBsZWdlbmQuIFRoZXNlIGluY2x1ZGU6IA0KDQo8cCBhbGlnbj0iY2VudGVyIj48ZGl2IGNsYXNzPSJ6b29tIj48aW1nIHNyYz0gIkltYWdlcy9iaXNjYWxlLWJpdmFyaWF0ZS1jb2xvcnMucG5nIiBhbHQ9IkJpc2NhbGUgQml2YXJpYXRlIENvbG9yIFBhbGV0dGVzIiBzdHlsZT0id2lkdGg6MTAwJSI+PC9kaXY+PC9wPg0KDQpMaWtlIHRoZSB2aXN1YWxpemF0aW9uIHlvdSBjcmVhdGVkIGZvciBbRXhlcmNpc2UgMywgU3RlcCAzXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS00LyMxM19TdGVwX1RocmVlOl9UaGVfVmlzdWFsaXphdGlvbiksIHlvdSB3aWxsIHJlbHkgb24gc3ludGF4IGZyb20gYGNvd3Bsb3RgIHRvIG92ZXJsYXkgdGhlIG1hcCBhbmQgbGVnZW5kIGZyb20gYGJpc2NhbGVgLiBIb3dldmVyLCBjdXJyZW50bHkgdGhlIG9ubHkgZGVtb2dyYXBoaWMgZGF0YSBpbiB0aGlzIGV4ZXJjaXNlIGlzIGJ5IHJhY2UuIFNvIGJlZm9yZSB5b3UgYmVnaW4gdGhpcyBwcm9jZXNzIHlvdSBuZWVkIHRvIHRha2UgdGhlIGFkZGl0aW9uYWwgc3RlcCBvZiBjb25uZWN0aW5nIHRoZSBwb3B1bGF0aW9uIGRhdGEgZnJvbSBbRXhlcmNpc2UgMywgU3RlcCAyXShodHRwczovL2NocmlzbWdlbnRyeS5naXRodWIuaW8vR0lTMS1FeGVyY2lzZS0zLyMxMl9TdGVwX1R3bzpfVGhlX0FuYWx5c2VzKS4gVGhlIHNhbWUgc2NyaXB0IGNhbiBiZSB1c2VkIHRvIG9idGFpbiB0aGUgZGF0YXNldDoNCg0KYGBge3IgcG9wdWxhdGlvbiBkYXRhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9DQpwb3B1bGF0aW9uIDwtIHJlYWQuY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vY2hyaXNtZ2VudHJ5L0dJUzEtRXhlcmNpc2UtMy9tYWluL0RhdGEvbW9udF9jb19wb3AuY3N2JywgY29sQ2xhc3Nlcz1jKFRyYWN0PSJjaGFyYWN0ZXIiKSkNCmBgYA0KDQpUbyBjb25uZWN0IHRoZSBkYXRhIHRvIHRoZSBjZW5zdXMgdHJhY3QgZGF0YXNldCAqKl9jb21wbGV0ZV8qKiB0aGUgZm9sbG93aW5nIHNjcmlwdDoNCg0KYGBge3IgY29ubmVjdCBwb3AgZGF0YSB0byB0cmFjdHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0NCiNjZW5zdXNfd2l0aF9wb3AgPC0gbWVyZ2UoeCA9IGNlbnN1c190cmFjdF9kYXRhc2V0LCB5ID0gREFUQVNFVCwgYnkueCA9ICJWQVJJQUJMRSIsIGJ5LnkgPSAiVkFSSUFCTEUiLCBhbGwgPSBUUlVFKQ0KYGBgDQoNCklmIHlvdSBoYXZlIHF1ZXN0aW9ucyBhYm91dCBjb21wbGV0aW5nIHRoZSBzY3JpcHQgYWJvdmUgcmV2aWV3IHRoZSBpbmZvcm1hdGlvbiBmcm9tIFtFeGVyY2lzZSAzLCBTdGVwIDJdKGh0dHBzOi8vY2hyaXNtZ2VudHJ5LmdpdGh1Yi5pby9HSVMxLUV4ZXJjaXNlLTMvIzEyX1N0ZXBfVHdvOl9UaGVfQW5hbHlzZXMpIG9yIGZyb20gc2ltaWxhciBzdGVwcyBlYXJsaWVyIGluIHRoaXMgZXhlcmNpc2UuDQoNClRvIGNyZWF0ZSB0aGUgYml2YXJpYXRlIGRhdGFzZXQgeW91IG5lZWQgdG8gdXNlIHRoZSBgYmlfY2xhc3NgIGZ1bmN0aW9uIGZyb20gX2Jpc2NhbGVfLg0KDQpgYGB7ciBiaXZhcmlhdGUgZGF0YSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KYml2YXJpYXRlX2RhdGEgPC0gYmlfY2xhc3MoY2Vuc3VzX3dpdGhfcG9wLCB4ID0gdG90YWxfcG9wLCB5ID0gQkZfQ291bnQsIGRpbSA9IDMsIHN0eWxlID0gImplbmtzIikNCmBgYA0KDQpJbiB0aGlzIHNjcmlwdCB5b3UgaWRlbnRpZnkgdGhlIGRhdGFzZXQgdG8gYmUgdXNlZCB0byBjcmVhdGUgdGhlIF9iaV9jbGFzc18gZGF0YS4gWW91IGlkZW50aWZ5IHRoZSB4IHZhcmlhYmxlLCBpbiB0aGlzIGV4YW1wbGUgdG90YWwgcG9wdWxhdGlvbiBhbmQgdGhlIHkgdmFyaWFibGUgZm9yIHRoZSBjb3VudCBvZiBicm93bmZpZWxkcy4gRmluYWxseSB5b3UgcHJvdmlkZSB0aGUgbnVtYmVyIG9mIGRpbWVuc2lvbnMgKDMpIGFuZCBfc3R5bGVfIHRvIGNhbGN1bGF0ZSB0aGUgZGl2aXNpb25zIGluIHRoZSBkYXRhLiBGb3IgdGhpcyBleGFtcGxlIHlvdSB3aWxsIHVzZSBbSmVua3MgTmF0dXJhbCBCcmVha3MgQ2xhc3NpZmljYXRpb25dKGh0dHBzOi8vcHJvLmFyY2dpcy5jb20vZW4vcHJvLWFwcC9sYXRlc3QvaGVscC9tYXBwaW5nL2xheWVyLXByb3BlcnRpZXMvZGF0YS1jbGFzc2lmaWNhdGlvbi1tZXRob2RzLmh0bSkgc2ltcGx5IGlkZW50aWZpZWQgYXMgImplbmtzIi4gDQoNCk5vdyB5b3UgY2FuIHVzZSB0aGUgaW5mb3JtYXRpb24gYWJvdmUgdG8gY3JlYXRlIHRoZSB2aXN1YWxpemF0aW9uIGJhc2VkIG9uIHRvdGFsIHBvcHVsYXRpb24uIFlvdSB3aWxsIG5lZWQgdG8gY3JlYXRlIGEgbmV3IGNvZGUgYmxvY2sgb3IgYWx0ZXIgdGhlIG9uZSBhYm92ZSB0byBpZGVudGlmeSBhbiB4IHZhcmlhYmxlIGFwcHJvcHJpYXRlIHRvIGFuc3dlciB0aGUgcXVlc3Rpb25zIHBvc2VkIGJ5IHRoZSBDb3VudHkgQ29tbWlzc2lvbiBhbmQgSGVhbHRoIERlcGFydG1lbnQuDQoNCmBgYHtyIGJpdmFyaWF0ZSBtYXAgdG90YWwgcG9wLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9DQpiaXZhcmlhdGVfbWFwIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gYml2YXJpYXRlX2RhdGEsIG1hcHBpbmcgPSBhZXMoZmlsbCA9IGJpX2NsYXNzKSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IGJyb3duZmllbGRzX2RhdGFzZXQsIGFlcyh4PWxvbmcsIHk9bGF0KSwgY29sb3IgPSAicmVkIikgKyANCiAgYmlfc2NhbGVfZmlsbChwYWwgPSAiRGtWaW9sZXQiLCBkaW0gPSAzKSArDQogIHRoZW1lX3ZvaWQoKQ0KYGBgDQoNCllvdSBjYW4gdXNlIHRoaXMgc2FtZSBleGFtcGxlIHNjcmlwdCB0byBjcmVhdGUgYSBtYXAgYmFzZWQgb24gYSBkaWZmZXJlbnQgZGVtb2dyYXBoaWMgdmFyaWFibGUgKHgpIGFzIGxvbmcgYXMgaXQgaXMgaWRlbnRpZmllZCBhcHByb3ByaWF0ZWx5IGluIHRoZSAqKmJpdmFyaWF0ZV9kYXRhKiogc2NyaXB0IGJsb2NrIGFib3ZlLiBOZXh0IHlvdSBuZWVkIHRvIGNyZWF0ZSBhbiBvYmplY3QgdG8gc2VydmUgYXMgdGhlIGxlZ2VuZC4gVW5mb3J0dW5hdGVseSwgYmVjYXVzZSBgYmlzY2FsZWAgbGVnZW5kcyBhcmUgbm90IGxpbmtlZCB0byB0aGUgZGF0YSB5b3Ugd2lsbCBuZWVkIHRvIG92ZXJsYXkgaXQgYXMgYW4gImltYWdlIi4gU28gYmUgY2FyZWZ1bCB0aGF0IGFueSBjaGFuZ2VzIG1hZGUgdG8gdGhlIGRhdGEgYXJlIHJlZmxlY3RlZCBpbiB0aGUgbGVnZW5kIGFzIHdlbGwuDQoNCmBgYHtyIGJpdmFyaWF0ZSBtYXAgbGVnZW5kLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9DQpsZWdlbmQgPC0gYmlfbGVnZW5kKHBhbCA9ICJEa1Zpb2xldCIsDQogICAgICAgICAgICAgICAgICAgIGRpbSA9IDMsDQogICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiVG90YWwgUG9wdWxhdGlvbiIsDQogICAgICAgICAgICAgICAgICAgIHlsYWIgPSAiTm8uIEJyb3duZmllbGRzIiwNCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEwKQ0KYGBgDQoNCldpdGggdGhlIG1hcCBhbmQgbGVnZW5kIG9iamVjdHMgY3JlYXRlZCB5b3UgY2FuIG5vdyBzY3JpcHQgdGhlIGJhc2Ugb2YgdGhlIGZpbmFsIG1hcCB1c2luZyB0aGUgc2FtZSBwcm9jZXNzIGFzIHRoZSBbbGFzdCBleGVyY2lzZV0oaHR0cHM6Ly9jaHJpc21nZW50cnkuZ2l0aHViLmlvL0dJUzEtRXhlcmNpc2UtNC8jMTNfU3RlcF9UaHJlZTpfVGhlX1Zpc3VhbGl6YXRpb24pLg0KDQpgYGB7ciBmaW5hbCBtYXAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0NCmZpbmFsX21hcCA8LSBnZ2RyYXcoKSArDQogIGRyYXdfcGxvdChiaXZhcmlhdGVfbWFwLCAwLCAwLCAxLCAxKSArDQogIGRyYXdfcGxvdChsZWdlbmQsIDAuNywgMCwgMC4yNSwgMC4yNSkNCmZpbmFsX21hcA0KYGBgDQoNCkZvciB0aGlzIG1hcCwgdG90YWwgcG9wdWxhdGlvbiB3YXMgc2ltcGx5IHVzZWQgdG8gcHJvdmlkZSBhbiBleGFtcGxlIHNjcmlwdC4gU28gdG8gZmluaXNoIHRoaXMgZXhlcmNpc2UgeW91IHdpbGwgbmVlZCB0byBhbHRlciB0aGUgKip4KiogdmFyaWFibGUgaW4gdGhlIF9iaXZhcmlhdGVfZGF0YV8gc2NyaXB0IHRvIGRldGVybWluZSBpZiB0aGVyZSBpcyBhbnkgcmVsYXRpb25zaGlwIGJldHdlZW4gZGVtb2dyYXBoaWNzIChyYWNlIG9yIGFnZSkgZm9yIHRoZSBDb3VudHkgQ29tbWlzc2lvbiBhbmQgSGVhbHRoIERlcGFydG1lbnQuIA0KDQo8YmlnPjxiPlF1ZXN0aW9uIE5vLiA0PC9iPjwvYmlnPg0KPGJsb2NrcXVvdGU+DQpXaGljaCBjZW5zdXMgdHJhY3QgY29udGFpbnMgdGhlIG1vc3QgYnJvd25maWVsZHM/DQo8L2Jsb2NrcXVvdGU+DQoNCjwvZGV0YWlscz4NCg0KIyBUaGUgV3JpdGUtVXANCg0KSW4gdGhlIHJlcG9ydCB5b3UgcHJvdmlkZSB0byB0aGUgQ291bnR5IENvbW1pc3Npb24sIFN0b3Jtd2F0ZXIgTWFuYWdlbWVudCwgSGVhbHRoIERlcGFydG1lbnQsIGFuZCBUREVDIHBsZWFzZSBwcm92aWRlIHRoZSBmb2xsb3dpbmcgaW5mb3JtYXRpb246DQoNCi0gV2hpY2ggd2F0ZXJzaGVkIGlzIG1vc3QgcG90ZW50aWFsbHkgaW1wYWN0ZWQgYnkgYnJvd25maWVsZHM/DQotIFdoYXQgaXMgdGhlIHRvdGFsIHBvcHVsYXRpb24gb2YgdGhlIHRyYWN0cyB3aXRoIGJyb3duZmllbGRzPw0KLSBXaGF0IGRlbW9ncmFwaGljIGNvdWxkIGJlIHRoZSBtb3N0IGltcGFjdGVkIGJ5IGJyb3duZmllbGRzPw0KICAtIEJ5IGV4YW1pbmluZyB0aGUgdHJhY3Qgd2l0aCB0aGUgbW9zdCBicm93bmZpZWxkcywgd2hhdCBkZW1vZ3JhcGhpYyBpcyB0aGUgbW9zdCBpbXBhY3RlZCwgYW5kIGhvdyBkb2VzIGl0IHJlbGF0ZSB0byBsb2NhdGlvbiB3aXRoaW4gdGhlIGNpdHkvY291bnR5Pw0KDQpCZSBzdXJlIHRvIGluY2x1ZGUgbXBhcyB5b3UgY3JlYXRlZCB0byBzdXBwb3J0IHlvdXIgcmVwb3J0LiBXaGVuIGNvbXBsZXRlLCBzZW5kIGEgbGluayB0byB5b3VyIF9Db2xhYiBOb3RlYm9va18gb3Igd29yZCBkb2N1bWVudCB3aXRoIGFuc3dlcnMgdG8gUXVlc3Rpb25zIDEtNCBhbmQgeW91ciBjb21wbGV0ZWQgbWFwKHMpIHZpYSBlbWFpbC4=