About the Exercise

In this exercise, we will explore building part of the data analysis tool Indiana Precipitation Explorer (INCIP), which is available on the myGeoHUB.org website at https://mygeohub.org/tools/incip. Along the way, we will get to know a few core components of the R Programming Language like the data frame data structure, learn a little bit about manipulating data with R using the dplyr library, and build a web application interface that can be deployed on the HUB.

In the previous presentation, you saw examples of Shiny applications, and RMarkdown Documents that could be compiled into static web pages, used as notebooks for a more literate style of computing, or combined with Shiny widgets to create interactive documents. Today we will use historical precipitation data from the National Oceanic and Atmospheric Administration (NOAA) to build a map showing the mean hourly precipitation for hours with measurable precipitation. As we transform our map, we’ll keep the old versions and, in the end, we’ll build a web page to display them using one of the RMarkdown templates.

Maps we will be building in this tutorial

Maps we will be building in this tutorial


RStudio IDE And RMarkdown Tips

If you are new to the RStudio IDE, here are some tips to get you started. If you know all this stuff, skip down to the next section labeled 1. Loading the Data.


Expand the Code Pane

When you first open RStudio, give yourself some room by expanding the code pane. Press console pane’s minimize button to shrink it and pull the main horizontal divider to the right to expand the code pane.

Give yourself plenty of elbow room as you code by expanding the code pane.

Give yourself plenty of elbow room as you code by expanding the code pane.

Markdown and Code Chunks

The RMarkdown document we will be editing has both Markdown and code chunks in it. The markdown looks like plain text or wiki syntax. The code chunks start and end with three backticks and have a grey background, like this:

```{r}
 I'm a code chunk!
```

In a code chunk, there are two controls you can use to run code. They are both located in the upper right corner of the code chunk. Pressing the Run previous code chunk. button will execute all code chunks above the current chunk. Pressing the Run current code chunk. button will execute the current code chunk.

Markdown looks like plain text and wiki syntax. Code chunks have a grey background. Use the green play button in the upper right corner to execute the current code chunk. The results will be displayed below the code chunk.

Markdown looks like plain text and wiki syntax. Code chunks have a grey background. Use the green play button in the upper right corner to execute the current code chunk. The results will be displayed below the code chunk.

Knitting the Document

To compile or render the document, use the Knit (Knit Button.) button located just above the Code Pane. This will turn your completed RMarkdown file into a HTML document and launch the document in a new window for you to view.

Press the Knit" button just above the code pane to convert your RMarkdown document into an HTML Document.

Press the “Knit”" button just above the code pane to convert your RMarkdown document into an HTML Document.

Clear the Session’s Variables

If you run the code chunks out of order, you may find that some of the variables have been modified unexpectedly. This could be the cause of maps not showing up correctly in this tutorial. One possible resolution is to clear the session’s variables and run all of the code chunks again in order. Use the Session->Clear Workspace menu item from the top of the RStudio IDE to clear out the values for all variables. Then press the Run Previous Chunks. button to run the code chunks above the current chunk, and press the Run Current Chunk. button to run the current code chunk.

The Session -> Clear Workspace menu item will remove all variables from the current R session so you can start over.

The Session -> Clear Workspace menu item will remove all variables from the current R session so you can start over.

1. Loading the data

The precipitation data is held in comma separated value (CSV) files that are stored on MyGeoHUB. From the RStudio IDE running on MyGeoHUB, we can access the files in the directory /data/tools/incip/indiana_precipitation. Inside the tutorial’s setup code chunk, on line 19, you’ll see the variable precip.dir is setup to hold the path of the directory where the data files live. It looks like this:

# setup the directory where the precipitation data lives
data.dir = "/data/tools/incip"
precip.dir = file.path(data.dir,'indiana_precipitation')

The directory holds a file named stations.csv.clean with the id, name, latitude, and longitude for each station. On lines 25-27, the CSV file is read into a data structure called a Data Frame. You can think of a Data Frame as a table that you can query. The R language’s dplyr library has a number of functions, like filter, mutate, and select, that are helpful for querying and manipulating information in data frames.

The stations.df data frame looks like this:

Along with the stations.csv.clean file, the precip.dir directory holds the precipitation data files for each station. The data files have two columns, Time and Precipitation. Lines 29-59 read in the precipitation data files and merge them with information about the monitoring station like the id, name, latitude and longitude. On lines 52-54, we use the filter function find the row with information about the monitoring station we are currently processing and the mutate function to add a new column, named data, to the row. At the end we store the modified row in a the precip.details.df data frame.

Our new data frame, precip.details.df, holds station information and precipitation data in a single location. If we take a look at it, we see that the precipitation data is stored in a column named data with the type list. We can index into the list to access the Time and Precipitation columns of the data frame for each monitor station. This is what precip.details.df looks like:

The monitor station information comes with longitude and latitude coordinates. Let’s see what the monitor station locations look like when plotted on a map. We can use the R’s Leaflet library to setup a view of the state of Indiana and place markers at the location of each monitor station. By default, the markers will be colored blue.


Your Turn: Display the Station Locations

Find the code chunk labeled create_map_object, around line 68, and execute it pressing the green play button (Run Button.) in the upper right corner of the chunk. Your map will show up underneath the code chunk and should look like this:


2. Calculating Precipitation Means

Seeing the locations of each monitor station only tells half the story. It would be interesting to finding out if there are trends in precipitation amounts across the state. Since we have the precipitation data for each monitor station, we can find the average hourly precipitation over the years the data was collected. Then we can color each marker based on this average to help us visually compare the the precipitation around the state.

Let’s start by updating our data frame, precip.details.df, with the mean precipitation for each station. Here is a reminder of what the data frame looks like:

In the code chunk labeled calculate_precipitaion_means, line 87, we calculate the mean of the precipitation values held in the data column and store the values back into our data frame in a column named mean. The updated data frame is shown below.

precip.details.df %<>%
  group_by(id) %>%
  mutate(mean = mean(data[[1]][2]$Precipitation)) %>%
  ungroup()

precip.details.df


Your Turn: Calculate the Means

For the code chunk labeled calculate_precipitation_means, press the Run Button. button to run the code chunk and update the data frame. There is no output from this code chunk.


A convenient way of displaying the mean precipitation data on the map is to color the markers based on a range of precipitation values. This allows users to visually inspect the map and estimate which stations may have a higher or lower mean precipitation. Let’s use the colorBin() function to group the mean values into five equal sized bins and assign a color to each bin. The colorBin() function accepts a color palette, a list of values, and the number of bins to group values into. It returns a function, that we will store in the variable qpal, that can be called to query the color bin that a value falls into.

For example, in the code below, we create a queryable palette, named qpal, by specifying a color palette (palette = "Blues"), the domain or range of our values (a random uniform distribution of 10 numbers between 0 and 1), and the number of bins we want the values to fall within (nbins = 5):

palette = "Blues"
values = runif(10,min=0,max=1)
nbins = 5

qpal = colorBin(palette,values,nbins)

Above, we used random numbers for our values variable. Let’s see what color bins they end up falling into:

#EFF3FF
0.429879865143448
#EFF3FF
0.458758843364194
#EFF3FF
0.496266099624336
#C6DBEF
0.550312276463956
#C6DBEF
0.55441257241182
#6BAED6
0.714308749884367
#6BAED6
0.797221049899235
#3182BD
0.853515577036887
#08519C
0.910392062272877
#08519C
0.911753485677764


Your Turn: Create a Queryable Palette

Now it’s your turn to create a queryable palette for our map markers. In the code chunk labeled calculate_color_from_mean, line 97, use the colorBin() function to generate a palette for our precipitation means. Be sure to fill in these three items:

  1. Choose a color palette (Line 105)
  2. Specify the domain for our precipication mean values (Line 116)
  3. Set the number of bins the values can fall into (Line 121)

Your code should look something like this:

# YOUR TURN:
# On the next line, try setting palette to one of the following:
#   "RdYlBu"
#   "Blues"
#   "YlOrRd"
# check out http://colorbrewer2.org/ for more palettes
# I like "YlOrRd"
palette = "YlOrRd"

# YOUR TURN:
# Set the domain of values to the mean column in our data frame:
#   precip.details.df$mean
values = precip.details.df$mean

# YOUR TURN:
# Choose the number of bins. A good choice is an integer between 2 and 7
# I like 5
nbins = 5

# Create a palette we can query for which bin a value falls into.
qpal = colorBin(palette,values,nbins)

# Add a column named 'color' to our data frame. It holds
# the bin each station's mean precipitation falls into.
precip.details.df %<>%
  mutate(color = qpal(mean))

When you have completed updating the code chunk, run it by pressing the Run Button. button in the code chunk controls.


Great! Our updated data frame now has a column named color, which describes which bin the mean precipitation value falls into. Let’s have a look:

The next task is to update our map to show our custom color for the marker instead of the default blue color. In the code chunk labeled plot_station_locations_with_colors, line 135, we create a map using the leaflet() function and then use the addCircleMarkers() function to place circle markers on the map at the locations of the monitor stations. We need to update this map declaration to use the values we stored in the color column of our data frame.


Your Turn: Color the Map Markers

Add the following argument to the addCircleMarkers() function to tell the map to color the markers using the color column we generated earlier from our custom color palette and bins:

color = ~color

After you have made the change, your code chunk should look like this:

map <- leaflet(precip.details.df %>% select(-data)) %>%
        addTiles()

map %>%
  # create the binned color marker
  addCircleMarkers(
    label = ~name,
    lng = ~longitude,
    lat = ~latitude,
    radius = 4,
    opacity = 1,
    fillOpacity = 1,
    # YOUR TURN:
    # On the next line, add the argument: color = ~color,
    color = ~color,
    weight = 1
  )


Your Turn: Generate an Updated Map

Run the code chunk, using the Run Button. button in the upper right corner of the chunk, to see what the updated map looks like. The markers should now be a range of colors, similar to this one:


3. Add Marker Borders

The markers now show another dimension of information from our data frame, the binned mean precipitation. If you used the ‘YlOrRd’ palette, you may notice that some of the markers are a little hard to see. For example, the light yellow marker in the north central part of Indiana, near the city of South Bend, almost blends in with base map background. One easy way to solve this problem is to place a slightly larger black marker behind the marker displaying our bin color. This will give the effect of the marker having a border, helping to distinguish it from other artifacts on the map.

In the code chunk labeled add_black_background_marker, line 161, we create two types of markers on the map. The first marker is a black marker that will act as a border. The second marker sits on top of the black marker and shows the binned color for the mean precipitation value.


Your Turn: Create Background Markers

Modify the first marker in the code chunk to:

  1. Set addCircleMarkers()’s color argument to “#000000”, the hexadecimal value for the HTML color representing black.
  2. Set the line width (weight) to 3, a value slightly larger than that of the second marker.

After you have made the change, the code chunk should look something like this:

map %<>%
  # create the black border marker
  addCircleMarkers(
    lng = ~longitude,
    lat = ~latitude,
    radius = 4,
    opacity=1,
    fillOpacity = 0,
    # YOUR TURN:
    # 1. Set the color argument to "#000000"
    color = "#000000",
    # YOUR TURN:
    # 2. Set the weight argument to 3
    weight = 3
  ) %>%
  # create the bin color marker
  addCircleMarkers(
    label = ~name,
    lng = ~longitude,
    lat = ~latitude,
    radius = 4,
    opacity = 1,
    fillOpacity = 1,
    color = ~color,
    weight = 1
  )


Your Turn: View Map with Updated Markers

Now run the code chunk to confirm that the updated map shows a border around the markers. Press the Run Button. button in the upper right corner of the chunk to execute the code.


4. Add a Legend to the Map

The black border around the colored marker helps users distinguish them from a similarly colored background. The map is missing one more item. No map is complete without a legend and it is especially important in this case. Having the colored markers on the map looks nice, but without the legend, users don’t know what the colors mean.

We’ll use the addLegend() function to add a legend to the map. In the code chunk labeled add_legend_to_map, line 194, the addLegend() function accepts a number of parameters telling the map how to configure the legend, like title, placement, and background opacity.


Your Turn: Setup Map Legend

Adjust the following parameters:

  1. Set the pal argument to qpal, the name of our custom binned color palette function.
  2. Set the values argument to ~mean, the column in our data frame that holds the calculated mean precipitation values.

After making the adjustments, the code chunk should look like this:

map %<>% 
  addLegend(
    "bottomright",
    title = "<center>Mean Hourly<br>
             Precipitation<br/>
             <small>
               for hours with<br/>
               measurable<br/>
               precipitation
             </small></center>",
    opacity = 1,
    labFormat = labelFormat(suffix="in"),
    # YOUR TURN:
    # Set the pal argument to our custom binned palette function, qpal
    pal = qpal,
    # YOUR TURN:
    # Set the values argument to the mean precipitation values, ~mean
    values = ~mean
  )


Your Turn: View Map with Legend

Execute the code in the code chunk using the Run Button. button in the upper right corner of the chunk. Do you see our new legend on the map? It should show what values the marker colors correspond to.


5. Putting it all Together

You may not have noticed, but the file we have been editing is actually an RMarkdown document. We have been mixing our R code with Markdown wiki syntax and executing the code chunks just as we would in a literate computing style Notebook.

If you go back through the code you may notice syntax in between the code chunks like this:

Row
-------------------------------------

### Step #1 - Precipitation Monitor Stations

and like this:

### Step #4 - Add a legend to the map

These are RMarkdown wiki syntax that give hints about how to format the file when rendered as a web page. At the top of the file, exists this YAML declaration:

---
title: Exploring Precipitation Across Indiana
output:
  flexdashboard::flex_dashboard:
    orientation: rows
---

All RMarkdown files have a YAML declaration at the top. This one states that the file should be rendered as a FlexDashboard, which is one of the RMarkdown templates that allow developers to quickly generate a dashboard from the R and Markdown code in the file. There are a number of different styles of FlexDashboards and you can learn more about them at http://rmarkdown.rstudio.com/flexdashboard/.

Our FlexDashboard contains a 2x2 grid of the maps we have created today. We can render it to HTML by using the Knit (Knit Button.) button near the top of the RStudio IDE.


Your Turn: Generate an HTML Document

Press the Knit Button. button, just above the code pane, to generate and view our HTML document. A new window should pop up with all of the maps you generated in this exercise.

Maps we built in this tutorial.

Maps we built in this tutorial.


6. Use the Map for Analysis

Now that we have built a web page that displays our station locations on a map and shows us mean hourly precipitation for hours with measurable precipitation, let’s use that map to learn something new!

Visually inspect the map.

  1. Is there a trend in the recorded mean hourly precipication across the state of Indiana?
  2. Can you tell which station looks like it has the highest mean hourly precipitation?

We can use the filter() and select() functions to query this information from the data frame to confirm our suspicion. The filter() function finds the row where the mean column is equal to the max() of all values in the column. The select() function returns the name column for that row.

highmean.station.name <- precip.details.df %>%
                           filter(mean == max(mean)) %>%
                           select(name) %>%
                           .[[1]]

Did you pick the PRINCETON 1 W station?


Exercise Completed!

Congratulations, you have completed this exercise. In the next section, you will learn more about publishing applications like this on the HUBzero Platform.

LS0tCnRpdGxlOiAiRXhwbG9yaW5nIFByZWNpcGl0YXRpb24gQWNyb3NzIEluZGlhbmEiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogNgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCgo8c3R5bGU+CgovKmNlbnRlciBtYXBzIGhvcml6b250YWxseSBvbiB0aGUgcGFnZSovCi5odG1sLXdpZGdldCB7CiAgbWFyZ2luOiAwIGF1dG87Cn0KCi8qY2VudGVyIHRoZSB0aXRsZSBvZiB0aGUgZG9jdW1lbnQqLwpoMS50aXRsZSB7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgovKmNlbnRlciBpbWFnZXMgaW4gYSBkaXYqLwoudHV0aW1nIHsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCi8qaGlnaGxpZ2hpbmcgZm9yIHRoZSAiWU9VUiBUVVJOOiIiIGhlYWRlcnMqLwpoNSB7CiAgY29sb3I6IHJlZDsKICBmb250LXdlaWdodDogYm9sZDsKfQoKLyoyIGNvbHVtbiBsYXlvdXQgZm9yIGhpbnRzKi8KLmNvbHVtbi1sZWZ0LTJ7CiAgZmxvYXQ6IGxlZnQ7CiAgd2lkdGg6IDQ4JTsKICBtYXJnaW46IDElOwp9CgovKjQgY29sdW1uIGxheW91dCBmb3IgaGludHMqLwouY29sdW1uLWxlZnQtNHsKICBmbG9hdDogbGVmdDsKICB3aWR0aDogMjMlOwogIG1hcmdpbjogMSU7Cn0KCi8qa2VlcCAyIGFuZCA0IGNvbHVtbiBsYXlvdXQgZnJvbSB3cmFwcGluZyBpbmFwcHJvcHJpYXRlbHkqLwouY2xlYXJmaXg6OmFmdGVyIHsKICBjb250ZW50OiAiIjsKICBjbGVhcjogYm90aDsKICBkaXNwbGF5OiB0YWJsZTsKfQoKLmNvbG9yc3dhdGNoIHsKICB0ZXh0LWFsaWduOmNlbnRlcjsKICB3aWR0aDogMTAwJTsKICBoZWlnaHQ6IDJlbTsKICBib3JkZXItc3R5bGU6IHNvbGlkOwogIGJvcmRlci1jb2xvcjogIzAwMDAwMDsKfQoKLmNvbG9yc3dhdGNodGV4dCB7CiAgdGV4dC1hbGlnbjogbGVmdDsKfQo8L3N0eWxlPgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9Cgprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLmFsaWduPSdjZW50ZXInKQoKIyBsb2FkIGluIHJlcXVpcmVkIGxpYnJhcmllcwpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeShyZWFkcikKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KGh0bWx0b29scykKCmFkZENvbG9yU3dhdGNoIDwtIGZ1bmN0aW9uKGNvbG9yLHZhbHVlKSB7CiAgc3R5bGUgPSBwYXN0ZSgiYmFja2dyb3VuZDoiLGNvbG9yLHNlcD0iIikKICBkaXYoY2xhc3MgPSAiY2xlYXJmaXgiLAogICAgICBkaXYoY2xhc3MgPSAiY29sdW1uLWxlZnQtMiIsCiAgICAgICAgICBkaXYoY2xhc3MgPSAiY29sb3Jzd2F0Y2giLCBzdHlsZT1zdHlsZSwgY29sb3IpCiAgICAgICksCiAgICAgIGRpdihjbGFzcyA9ICJjb2x1bW4tbGVmdC0yIGNvbG9yc3dhdGNodGV4dCIsIHZhbHVlKQogICkKfQoKc2hvd1BhbGV0dGVDb2xvcnMgPC0gZnVuY3Rpb24ocXBhbCwgdmFsdWUpIHsKIyA8ZGl2IGNsYXNzPSJjbGVhcmZpeCI+CiMgPGRpdiBjbGFzcz0iY29sdW1uLWxlZnQtMiI+CiMgPGRpdiBjbGFzcz0iY29sb3Jzd2F0Y2giIHN0eWxlPSJiYWNrZ3JvdW5kOiNGMDNCMjAiPiYjMzU7RjAzQjIwPC9kaXY+CiMgPC9kaXY+IDwhLS0gY29sdW1uLWxlZnQtMiAtLT4KIyA8ZGl2IGNsYXNzPSJjb2x1bW4tbGVmdC0yIGNvbG9yc3dhdGNodGV4dCI+CiMgMC45ODMyMwojIDwvZGl2PiA8IS0tIGNvbHVtbi1sZWZ0LTIgLS0+CiMgPC9kaXY+IDwhLS0gY2xlYXJmaXggLS0+CiAgCiAgYWRkQ29sb3JTd2F0Y2ggPC0gZnVuY3Rpb24oY29sb3IsdmFsdWVzKSB7CiAgICBzdHlsZSA9IHBhc3RlKCJiYWNrZ3JvdW5kOiIsY29sb3Isc2VwPSIiKQogICAgZGl2KGNsYXNzID0gImNsZWFyZml4IiwKICAgICAgICBkaXYoY2xhc3MgPSAiY29sdW1uLWxlZnQtMiIsCiAgICAgICAgICAgIGRpdihjbGFzcyA9ICJjb2xvcnN3YXRjaCIsIHN0eWxlPXN0eWxlLCBjb2xvcikKICAgICAgICApLAogICAgICAgIGRpdihjbGFzcyA9ICJjb2x1bW4tbGVmdC0yIGNvbG9yc3dhdGNodGV4dCIsIHZhbHVlKQogICAgKQogIH0KICAKICB0IDwtICIiCiAgZm9yICh2YWx1ZSBpbiB2YWx1ZXMpIHsKICAgIGNvbG9yID0gcXBhbCh2YWx1ZSkKICAgIHQgPC0gcGFzdGUodCxhZGRDb2xvclN3YXRjaChjb2xvcix2YWx1ZSkpCiAgfQogIAogIHJldHVybih0KQp9CmBgYAoKPGJyLz4KCiMjIyBBYm91dCB0aGUgRXhlcmNpc2UKCkluIHRoaXMgZXhlcmNpc2UsIHdlIHdpbGwgZXhwbG9yZSBidWlsZGluZyBwYXJ0IG9mIHRoZSBkYXRhIGFuYWx5c2lzIHRvb2wgSW5kaWFuYSBQcmVjaXBpdGF0aW9uIEV4cGxvcmVyIChJTkNJUCksIHdoaWNoIGlzIGF2YWlsYWJsZSBvbiB0aGUgbXlHZW9IVUIub3JnIHdlYnNpdGUgYXQgaHR0cHM6Ly9teWdlb2h1Yi5vcmcvdG9vbHMvaW5jaXAuIEFsb25nIHRoZSB3YXksIHdlIHdpbGwgZ2V0IHRvIGtub3cgYSBmZXcgY29yZSBjb21wb25lbnRzIG9mIHRoZSBSIFByb2dyYW1taW5nIExhbmd1YWdlIGxpa2UgdGhlICpkYXRhIGZyYW1lKiBkYXRhIHN0cnVjdHVyZSwgbGVhcm4gYSBsaXR0bGUgYml0IGFib3V0IG1hbmlwdWxhdGluZyBkYXRhIHdpdGggUiB1c2luZyB0aGUgKmRwbHlyKiBsaWJyYXJ5LCBhbmQgYnVpbGQgYSB3ZWIgYXBwbGljYXRpb24gaW50ZXJmYWNlIHRoYXQgY2FuIGJlIGRlcGxveWVkIG9uIHRoZSBIVUIuCgpJbiB0aGUgcHJldmlvdXMgcHJlc2VudGF0aW9uLCB5b3Ugc2F3IGV4YW1wbGVzIG9mIFNoaW55IGFwcGxpY2F0aW9ucywgYW5kIFJNYXJrZG93biBEb2N1bWVudHMgdGhhdCBjb3VsZCBiZSBjb21waWxlZCBpbnRvIHN0YXRpYyB3ZWIgcGFnZXMsIHVzZWQgYXMgbm90ZWJvb2tzIGZvciBhIG1vcmUgbGl0ZXJhdGUgc3R5bGUgb2YgY29tcHV0aW5nLCBvciBjb21iaW5lZCB3aXRoIFNoaW55IHdpZGdldHMgdG8gY3JlYXRlIGludGVyYWN0aXZlIGRvY3VtZW50cy4gVG9kYXkgd2Ugd2lsbCB1c2UgaGlzdG9yaWNhbCBwcmVjaXBpdGF0aW9uIGRhdGEgZnJvbSB0aGUgTmF0aW9uYWwgT2NlYW5pYyBhbmQgQXRtb3NwaGVyaWMgQWRtaW5pc3RyYXRpb24gKE5PQUEpIHRvIGJ1aWxkIGEgbWFwIHNob3dpbmcgdGhlIG1lYW4gaG91cmx5IHByZWNpcGl0YXRpb24gZm9yIGhvdXJzIHdpdGggbWVhc3VyYWJsZSBwcmVjaXBpdGF0aW9uLiBBcyB3ZSB0cmFuc2Zvcm0gb3VyIG1hcCwgd2UnbGwga2VlcCB0aGUgb2xkIHZlcnNpb25zIGFuZCwgaW4gdGhlIGVuZCwgd2UnbGwgYnVpbGQgYSB3ZWIgcGFnZSB0byBkaXNwbGF5IHRoZW0gdXNpbmcgb25lIG9mIHRoZSBSTWFya2Rvd24gdGVtcGxhdGVzLiAKCjxkaXYgY2xhc3M9InR1dGltZyI+CiFbTWFwcyB3ZSB3aWxsIGJlIGJ1aWxkaW5nIGluIHRoaXMgdHV0b3JpYWxdKGltYWdlcy90dXRvcmlhbF9yZXN1bHQucG5nKXt3aWR0aD03MCV9CjwvZGl2PgoKPGJyLz4KCiMjIyBSU3R1ZGlvIElERSBBbmQgUk1hcmtkb3duIFRpcHMKCklmIHlvdSBhcmUgbmV3IHRvIHRoZSBSU3R1ZGlvIElERSwgaGVyZSBhcmUgc29tZSB0aXBzIHRvIGdldCB5b3Ugc3RhcnRlZC4KSWYgeW91IGtub3cgYWxsIHRoaXMgc3R1ZmYsIHNraXAgZG93biB0byB0aGUgbmV4dCBzZWN0aW9uIGxhYmVsZWQgKioxLiBMb2FkaW5nIHRoZSBEYXRhKiouCgo8YnIvPgoKCiMjIyMgRXhwYW5kIHRoZSBDb2RlIFBhbmUKCjxkaXYgY2xhc3M9ImNsZWFyZml4Ij4KPGRpdiBjbGFzcz0iY29sdW1uLWxlZnQtMiI+CldoZW4geW91IGZpcnN0IG9wZW4gUlN0dWRpbywgZ2l2ZSB5b3Vyc2VsZiBzb21lIHJvb20gYnkgZXhwYW5kaW5nIHRoZSBjb2RlIHBhbmUuIFByZXNzIGNvbnNvbGUgcGFuZSdzIG1pbmltaXplIGJ1dHRvbiB0byBzaHJpbmsgaXQgYW5kIHB1bGwgdGhlIG1haW4gaG9yaXpvbnRhbCBkaXZpZGVyIHRvIHRoZSByaWdodCB0byBleHBhbmQgdGhlIGNvZGUgcGFuZS4KPC9kaXY+IDwhLS0gY29sdW1uLWxlZnQtMiAtLT4KCjxkaXYgY2xhc3M9ImNvbHVtbi1sZWZ0LTIiPgogICFbR2l2ZSB5b3Vyc2VsZiBwbGVudHkgb2YgZWxib3cgcm9vbSBhcyB5b3UgY29kZSBieSBleHBhbmRpbmcgdGhlIGNvZGUgcGFuZS5dKGltYWdlcy90dXRvcmlhbF9oaW50c18yYS5wbmcpey5pbWctcmVzcG9uc2l2ZX0KPC9kaXY+IDwhLS0gY29sdW1uLWxlZnQtMiAtLT4KPC9kaXY+IDwhLS0gY2xlYXJmaXgtLT4KCgojIyMjIE1hcmtkb3duIGFuZCBDb2RlIENodW5rcwoKPGRpdiBjbGFzcz0iY2xlYXJmaXgiPgo8ZGl2IGNsYXNzPSJjb2x1bW4tbGVmdC0yIj4KVGhlIFJNYXJrZG93biBkb2N1bWVudCB3ZSB3aWxsIGJlIGVkaXRpbmcgaGFzIGJvdGggTWFya2Rvd24gYW5kIGNvZGUgY2h1bmtzIGluIGl0LiBUaGUgbWFya2Rvd24gbG9va3MgbGlrZSBwbGFpbiB0ZXh0IG9yIHdpa2kgc3ludGF4LiBUaGUgY29kZSBjaHVua3Mgc3RhcnQgYW5kIGVuZCB3aXRoIHRocmVlIGJhY2t0aWNrcyBhbmQgaGF2ZSBhIGdyZXkgYmFja2dyb3VuZCwgbGlrZSB0aGlzOgoKYGBgCmALYGB7cn0KIEknbSBhIGNvZGUgY2h1bmshCmALYGAKYGBgCgpJbiBhIGNvZGUgY2h1bmssIHRoZXJlIGFyZSB0d28gY29udHJvbHMgeW91IGNhbiB1c2UgdG8gcnVuIGNvZGUuIFRoZXkgYXJlIGJvdGggbG9jYXRlZCBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyIG9mIHRoZSBjb2RlIGNodW5rLiBQcmVzc2luZyB0aGUgIVtSdW4gcHJldmlvdXMgY29kZSBjaHVuay5dKGltYWdlcy9ydW5fcHJldmlvdXNfY29kZV9idXR0b24ucG5nKSBidXR0b24gd2lsbCBleGVjdXRlIGFsbCBjb2RlIGNodW5rcyBhYm92ZSB0aGUgY3VycmVudCBjaHVuay4gUHJlc3NpbmcgdGhlICFbUnVuIGN1cnJlbnQgY29kZSBjaHVuay5dKGltYWdlcy9ydW5fY3VycmVudF9jb2RlX2J1dHRvbi5wbmcpIGJ1dHRvbiB3aWxsIGV4ZWN1dGUgdGhlIGN1cnJlbnQgY29kZSBjaHVuay4KPC9kaXY+IDwhLS1jb2x1bW4tbGVmdC0yIC0tPgoKPGRpdiBjbGFzcz0iY29sdW1uLWxlZnQtMiI+CiFbTWFya2Rvd24gbG9va3MgbGlrZSBwbGFpbiB0ZXh0IGFuZCB3aWtpIHN5bnRheC4gQ29kZSBjaHVua3MgaGF2ZSBhIGdyZXkgYmFja2dyb3VuZC4gVXNlIHRoZSBncmVlbiBwbGF5IGJ1dHRvbiBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyIHRvIGV4ZWN1dGUgdGhlIGN1cnJlbnQgY29kZSBjaHVuay4gVGhlIHJlc3VsdHMgd2lsbCBiZSBkaXNwbGF5ZWQgYmVsb3cgdGhlIGNvZGUgY2h1bmsuXShpbWFnZXMvdHV0b3JpYWxfaGludHNfNGEucG5nKXsuaW1nLXJlc3BvbnNpdmV9CjwvZGl2PiA8IS0tIGNvbHVtbi1sZWZ0LTIgLS0+CjwvZGl2PiA8IS0tIGNsZWFyZml4IC0tPgoKCiMjIyMgS25pdHRpbmcgdGhlIERvY3VtZW50Cgo8ZGl2IGNsYXNzPSJjbGVhcmZpeCI+CjxkaXYgY2xhc3M9ImNvbHVtbi1sZWZ0LTIiPgpUbyBjb21waWxlIG9yIHJlbmRlciB0aGUgZG9jdW1lbnQsIHVzZSB0aGUgKktuaXQqICghW0tuaXQgQnV0dG9uLl0oaW1hZ2VzL2tuaXRfYnV0dG9uLnBuZykpICBidXR0b24gbG9jYXRlZCBqdXN0IGFib3ZlIHRoZSBDb2RlIFBhbmUuIFRoaXMgd2lsbCB0dXJuIHlvdXIgY29tcGxldGVkIFJNYXJrZG93biBmaWxlIGludG8gYSBIVE1MIGRvY3VtZW50IGFuZCBsYXVuY2ggdGhlIGRvY3VtZW50IGluIGEgbmV3IHdpbmRvdyBmb3IgeW91IHRvIHZpZXcuCjwvZGl2PiA8IS0tIGNvbHVtbi1sZWZ0LTIgLS0+Cgo8ZGl2IGNsYXNzPSJjb2x1bW4tbGVmdC0yIj4KIVtQcmVzcyB0aGUgIktuaXQiIiBidXR0b24ganVzdCBhYm92ZSB0aGUgY29kZSBwYW5lIHRvIGNvbnZlcnQgeW91ciBSTWFya2Rvd24gZG9jdW1lbnQgaW50byBhbiBIVE1MIERvY3VtZW50Ll0oaW1hZ2VzL3R1dG9yaWFsX2hpbnRzXzYucG5nKXsuaW1nLXJlc3BvbnNpdmV9CjwvZGl2PiA8IS0tIGNvbHVtbi1sZWZ0LTIgLS0+CjwvZGl2PiA8IS0tIGNsZWFyZml4IC0tPgoKCiMjIyMgQ2xlYXIgdGhlIFNlc3Npb24ncyBWYXJpYWJsZXMKCjxkaXYgY2xhc3M9ImNsZWFyZml4Ij4KPGRpdiBjbGFzcz0iY29sdW1uLWxlZnQtMiI+CklmIHlvdSBydW4gdGhlIGNvZGUgY2h1bmtzIG91dCBvZiBvcmRlciwgeW91IG1heSBmaW5kIHRoYXQgc29tZSBvZiB0aGUgdmFyaWFibGVzIGhhdmUgYmVlbiBtb2RpZmllZCB1bmV4cGVjdGVkbHkuIFRoaXMgY291bGQgYmUgdGhlIGNhdXNlIG9mIG1hcHMgbm90IHNob3dpbmcgdXAgY29ycmVjdGx5IGluIHRoaXMgdHV0b3JpYWwuIE9uZSBwb3NzaWJsZSByZXNvbHV0aW9uIGlzIHRvIGNsZWFyIHRoZSBzZXNzaW9uJ3MgdmFyaWFibGVzIGFuZCBydW4gYWxsIG9mIHRoZSBjb2RlIGNodW5rcyBhZ2FpbiBpbiBvcmRlci4gVXNlIHRoZSAqU2Vzc2lvbi0+Q2xlYXIgV29ya3NwYWNlKiBtZW51IGl0ZW0gZnJvbSB0aGUgdG9wIG9mIHRoZSBSU3R1ZGlvIElERSB0byBjbGVhciBvdXQgdGhlIHZhbHVlcyBmb3IgYWxsIHZhcmlhYmxlcy4gVGhlbiBwcmVzcyB0aGUgIVtSdW4gUHJldmlvdXMgQ2h1bmtzLl0oaW1hZ2VzL3J1bl9wcmV2aW91c19jb2RlX2J1dHRvbi5wbmcpIGJ1dHRvbiB0byBydW4gdGhlIGNvZGUgY2h1bmtzIGFib3ZlIHRoZSBjdXJyZW50IGNodW5rLCBhbmQgcHJlc3MgdGhlICFbUnVuIEN1cnJlbnQgQ2h1bmsuXShpbWFnZXMvcnVuX2N1cnJlbnRfY29kZV9idXR0b24ucG5nKSBidXR0b24gdG8gcnVuIHRoZSBjdXJyZW50IGNvZGUgY2h1bmsuCjwvZGl2PiA8IS0tIGNvbHVtbi1sZWZ0LTIgLS0+Cgo8ZGl2IGNsYXNzPSJjb2x1bW4tbGVmdC0yIj4KIVtUaGUgU2Vzc2lvbiAtPiBDbGVhciBXb3Jrc3BhY2UgbWVudSBpdGVtIHdpbGwgcmVtb3ZlIGFsbCB2YXJpYWJsZXMgZnJvbSB0aGUgY3VycmVudCBSIHNlc3Npb24gc28geW91IGNhbiBzdGFydCBvdmVyLl0oaW1hZ2VzL3R1dG9yaWFsX2hpbnRzXzcucG5nKXsuaW1nLXJlc3BvbnNpdmV9CjwvZGl2PiA8IS0tIGNvbHVtbi1sZWZ0LTIgLS0+CjwvZGl2PiA8IS0tIGNsZWFyZml4IC0tPgoKCiMjIyAxLiBMb2FkaW5nIHRoZSBkYXRhCgpUaGUgcHJlY2lwaXRhdGlvbiBkYXRhIGlzIGhlbGQgaW4gY29tbWEgc2VwYXJhdGVkIHZhbHVlIChDU1YpIGZpbGVzIHRoYXQgYXJlIHN0b3JlZCBvbiBNeUdlb0hVQi4gRnJvbSB0aGUgUlN0dWRpbyBJREUgcnVubmluZyBvbiBNeUdlb0hVQiwgd2UgY2FuIGFjY2VzcyB0aGUgZmlsZXMgaW4gdGhlIGRpcmVjdG9yeSBgYGAvZGF0YS90b29scy9pbmNpcC9pbmRpYW5hX3ByZWNpcGl0YXRpb25gYGAuIEluc2lkZSB0aGUgdHV0b3JpYWwncyAqc2V0dXAqIGNvZGUgY2h1bmssIG9uIGxpbmUgMTksIHlvdSdsbCBzZWUgdGhlIHZhcmlhYmxlICpwcmVjaXAuZGlyKiBpcyBzZXR1cCB0byBob2xkIHRoZSBwYXRoIG9mIHRoZSBkaXJlY3Rvcnkgd2hlcmUgdGhlIGRhdGEgZmlsZXMgbGl2ZS4gSXQgbG9va3MgbGlrZSB0aGlzOgoKYGBge3IgZGF0YV9kaXJlY3Rvcnl9CiMgc2V0dXAgdGhlIGRpcmVjdG9yeSB3aGVyZSB0aGUgcHJlY2lwaXRhdGlvbiBkYXRhIGxpdmVzCmRhdGEuZGlyID0gIi9kYXRhL3Rvb2xzL2luY2lwIgpwcmVjaXAuZGlyID0gZmlsZS5wYXRoKGRhdGEuZGlyLCdpbmRpYW5hX3ByZWNpcGl0YXRpb24nKQpgYGAKClRoZSBkaXJlY3RvcnkgaG9sZHMgYSBmaWxlIG5hbWVkICpzdGF0aW9ucy5jc3YuY2xlYW4qIHdpdGggdGhlIGlkLCBuYW1lLCBsYXRpdHVkZSwgYW5kIGxvbmdpdHVkZSBmb3IgZWFjaCBzdGF0aW9uLiBPbiBsaW5lcyAyNS0yNywgdGhlIENTViBmaWxlIGlzIHJlYWQgaW50byBhIGRhdGEgc3RydWN0dXJlIGNhbGxlZCBhICpEYXRhIEZyYW1lKi4gWW91IGNhbiB0aGluayBvZiBhIERhdGEgRnJhbWUgYXMgYSB0YWJsZSB0aGF0IHlvdSBjYW4gcXVlcnkuIFRoZSBSIGxhbmd1YWdlJ3MgKmRwbHlyKiBsaWJyYXJ5IGhhcyBhIG51bWJlciBvZiBmdW5jdGlvbnMsIGxpa2UgYGBgZmlsdGVyYGBgLCBgYGBtdXRhdGVgYGAsIGFuZCBgYGBzZWxlY3RgYGAsICB0aGF0IGFyZSBoZWxwZnVsIGZvciBxdWVyeWluZyBhbmQgbWFuaXB1bGF0aW5nIGluZm9ybWF0aW9uIGluIGRhdGEgZnJhbWVzLgoKYGBge3IgcmVhZF9zdGF0aW9uX2F0dHJpYnV0ZXMsIG1lc3NhZ2U9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiMgcmVhZCBpbiBsb2NhdGlvbiBhbmQgZGVzY3JpcHRpb24gb2YgdGhlIHByZWNpcCBtb25pdG9yIHN0YXRpb25zCiMgc3RhdGlvbi5jc3YgaGFzIGR1cGxpY2F0ZSBlbnRyaWVzIGluIGl0ICgxMjE3MzkpLCBzbyB3ZSB1c2UgYQojIGNsZWFuIHZlcnNpb24gb2YgdGhlIGZpbGUsIHN0YXRpb24uY3N2LmNsZWFuLCB3aGVyZSB0aGUgc3RhdGlvbiBpZHMKIyBhcmUgdW5pcXVlLgoKIyBZT1VSIFRVUk46CiMgU2V0IHRoZSAnc3RhdGlvbnMuZm4nIHZhcmlhYmxlIGJlbG93IHRvICJzdGF0aW9uLmNzdi5jbGVhbiIKc3RhdGlvbnMuZm4gPSAic3RhdGlvbi5jc3YuY2xlYW4iCgpzdGF0aW9ucy5kZiA8LSByZWFkX2NzdiggZmlsZS5wYXRoKHByZWNpcC5kaXIsc3RhdGlvbnMuZm4pICkgJT4lCiAgICAgICAgICAgICAgICAgIHJlbmFtZShpZCA9IGBTdGF0aW9uIElEYCkgJT4lCiAgICAgICAgICAgICAgICAgIHJlbmFtZShuYW1lID0gYFN0YXRpb24gTmFtZWApCmBgYAoKVGhlICpzdGF0aW9ucy5kZiogZGF0YSBmcmFtZSBsb29rcyBsaWtlIHRoaXM6CgpgYGB7ciBzaG93X3N0YXRpb25zX2RmLCBlY2hvPUZBTFNFfQpzdGF0aW9ucy5kZgpgYGAKCkFsb25nIHdpdGggdGhlIHN0YXRpb25zLmNzdi5jbGVhbiBmaWxlLCB0aGUgKnByZWNpcC5kaXIqIGRpcmVjdG9yeSBob2xkcyB0aGUgcHJlY2lwaXRhdGlvbiBkYXRhIGZpbGVzIGZvciBlYWNoIHN0YXRpb24uIFRoZSBkYXRhIGZpbGVzIGhhdmUgdHdvIGNvbHVtbnMsIFRpbWUgYW5kIFByZWNpcGl0YXRpb24uIExpbmVzIDI5LTU5IHJlYWQgaW4gdGhlIHByZWNpcGl0YXRpb24gZGF0YSBmaWxlcyBhbmQgbWVyZ2UgdGhlbSB3aXRoIGluZm9ybWF0aW9uIGFib3V0IHRoZSBtb25pdG9yaW5nIHN0YXRpb24gbGlrZSB0aGUgaWQsIG5hbWUsIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUuIE9uIGxpbmVzIDUyLTU0LCB3ZSB1c2UgdGhlIGBgYGZpbHRlcmBgYCBmdW5jdGlvbiBmaW5kIHRoZSByb3cgd2l0aCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgbW9uaXRvcmluZyBzdGF0aW9uIHdlIGFyZSBjdXJyZW50bHkgcHJvY2Vzc2luZyBhbmQgdGhlIGBgYG11dGF0ZWBgYCBmdW5jdGlvbiB0byBhZGQgYSBuZXcgY29sdW1uLCBuYW1lZCAqZGF0YSosIHRvIHRoZSByb3cuIEF0IHRoZSBlbmQgd2Ugc3RvcmUgdGhlIG1vZGlmaWVkIHJvdyBpbiBhIHRoZSAqcHJlY2lwLmRldGFpbHMuZGYqIGRhdGEgZnJhbWUuCgpgYGB7ciBhZ2dyZWdhdGVfc3RhdGlvbl9kYXRhLCBtZXNzYWdlPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQojIHJlYWQgaW4gdGhlIHByZWNpcGl0YXRpb24gZGF0YQpwcmVjaXAuZGV0YWlscy5kZiA9IHRpYmJsZSgpCnByZWNpcC5maWxlcyA9IGxpc3QuZmlsZXMocGF0aD1wcmVjaXAuZGlyLHBhdHRlcm49ImhyLiouY3N2IikKCmZvciAoaSBpbiAxOmxlbmd0aChwcmVjaXAuZmlsZXMpKSB7CiAgIyBnZXQgdGhlIHN0YXRpb24gaWQgZnJvbSB0aGUgZmlsZSBwYXRoCiAgbWF0Y2hlcyA9IGdyZWdleHByKCJbMC05XSsiLHByZWNpcC5maWxlc1tpXSkKICAKICBzdGF0aW9uLmlkID0gYXMuaW50ZWdlcihyZWdtYXRjaGVzKHByZWNpcC5maWxlc1tpXSxtYXRjaGVzKVtbMV1dKQogIAogICMgZ2V0IGEgcHJlY2lwaXRhdGlvbiBmaWxlIHBhdGgKICBwcmVjaXAuZmlsZXBhdGggPSBmaWxlLnBhdGgocHJlY2lwLmRpcixwcmVjaXAuZmlsZXNbaV0pCiAgCiAgIyByZWFkIHRoZSBwcmVjaXBpdGF0aW9uIGRhdGEgaW50byBhIGRhdGFmcmFtZQogIGRmID0gcmVhZF9jc3YocHJlY2lwLmZpbGVwYXRoKQoKICAjIGNyZWF0ZSBhIHJvdyB3aXRoIFN0YXRpb25JRCwgU3RhdGlvbk5hbWUsIGxhdCwgbG9uIGluZm9ybWF0aW9uIGZyb20KICAjIHN0YXRpb25zLmRmLiBTdG9yZSB0aGUgcHJlY2lwaXRhdGlvbiBkYXRhZnJhbWUgaW4gYSBsaXN0LWNvbHVtbiBzbyB3ZQogICMgY2FuIHF1aWNrbHkgZ3JhYiBpdCBsYXRlciBieSBpbmRleGluZyBieSB0aGUgU3RhdGlvbiBJRC4KICBzdGF0aW9uLnJvdyA8LSBzdGF0aW9ucy5kZiAlPiUKICAgICAgICAgICAgICAgICAgIGZpbHRlcihpZCA9PSBzdGF0aW9uLmlkKSAlPiUKICAgICAgICAgICAgICAgICAgIG11dGF0ZShkYXRhID0gbGlzdChkZikpCgogICMgYnVpbGQgdXAgYSBuZXcgdGliYmxlLCByb3cgYnkgcm93LCB0aGF0IGxpbmtzIHN0YXRpb24gaW5mb3JtYXRpb24KICAjIHdpdGggdGhlIHByZWNpcGl0YXRpb24gZGF0YWZyYW1lLgogIHByZWNpcC5kZXRhaWxzLmRmID0gcmJpbmQocHJlY2lwLmRldGFpbHMuZGYsc3RhdGlvbi5yb3cpCn0KYGBgCgpPdXIgbmV3IGRhdGEgZnJhbWUsICpwcmVjaXAuZGV0YWlscy5kZiosIGhvbGRzIHN0YXRpb24gaW5mb3JtYXRpb24gYW5kIHByZWNpcGl0YXRpb24gZGF0YSBpbiBhIHNpbmdsZSBsb2NhdGlvbi4gSWYgd2UgdGFrZSBhIGxvb2sgYXQgaXQsIHdlIHNlZSB0aGF0IHRoZSBwcmVjaXBpdGF0aW9uIGRhdGEgaXMgc3RvcmVkIGluIGEgY29sdW1uIG5hbWVkICpkYXRhKiB3aXRoIHRoZSB0eXBlICpsaXN0Ki4gV2UgY2FuIGluZGV4IGludG8gdGhlIGxpc3QgdG8gYWNjZXNzIHRoZSBUaW1lIGFuZCBQcmVjaXBpdGF0aW9uIGNvbHVtbnMgb2YgdGhlIGRhdGEgZnJhbWUgZm9yIGVhY2ggbW9uaXRvciBzdGF0aW9uLiBUaGlzIGlzIHdoYXQgKnByZWNpcC5kZXRhaWxzLmRmKiBsb29rcyBsaWtlOgoKCgpgYGB7ciBzaG93X21lcmdlZF9kYXRhZnJhbWUsIGVjaG89RkFMU0V9CnByZWNpcC5kZXRhaWxzLmRmCmBgYAoKVGhlIG1vbml0b3Igc3RhdGlvbiBpbmZvcm1hdGlvbiBjb21lcyB3aXRoIGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUgY29vcmRpbmF0ZXMuIExldCdzIHNlZSB3aGF0IHRoZSBtb25pdG9yIHN0YXRpb24gbG9jYXRpb25zIGxvb2sgbGlrZSB3aGVuIHBsb3R0ZWQgb24gYSBtYXAuIFdlIGNhbiB1c2UgdGhlIFIncyBMZWFmbGV0IGxpYnJhcnkgdG8gc2V0dXAgYSB2aWV3IG9mIHRoZSBzdGF0ZSBvZiBJbmRpYW5hIGFuZCBwbGFjZSBtYXJrZXJzIGF0IHRoZSBsb2NhdGlvbiBvZiBlYWNoIG1vbml0b3Igc3RhdGlvbi4gQnkgZGVmYXVsdCwgdGhlIG1hcmtlcnMgd2lsbCBiZSBjb2xvcmVkIGJsdWUuCgo8YnIvPgoKIyMjIyMgWW91ciBUdXJuOiBEaXNwbGF5IHRoZSBTdGF0aW9uIExvY2F0aW9ucwpGaW5kIHRoZSBjb2RlIGNodW5rIGxhYmVsZWQgKmNyZWF0ZV9tYXBfb2JqZWN0KiwgYXJvdW5kIGxpbmUgNjgsIGFuZCBleGVjdXRlIGl0IHByZXNzaW5nIHRoZSBncmVlbiBwbGF5IGJ1dHRvbiAoIVtSdW4gQnV0dG9uLl0oaW1hZ2VzL3J1bl9jdXJyZW50X2NvZGVfYnV0dG9uLnBuZykpIGluIHRoZSB1cHBlciByaWdodCBjb3JuZXIgb2YgdGhlIGNodW5rLiBZb3VyIG1hcCB3aWxsIHNob3cgdXAgdW5kZXJuZWF0aCB0aGUgY29kZSBjaHVuayBhbmQgc2hvdWxkIGxvb2sgbGlrZSB0aGlzOgoKYGBge3IgcGxvdF9zdGF0aW9uX2xvY2F0aW9ucywgZWNobz1GQUxTRX0KbGVhZmxldChwcmVjaXAuZGV0YWlscy5kZiAlPiUgc2VsZWN0KC1kYXRhKSkgJT4lCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRDaXJjbGVNYXJrZXJzKAogICAgbGFiZWwgPSB+bmFtZSwKICAgIGxuZyA9IH5sb25naXR1ZGUsCiAgICBsYXQgPSB+bGF0aXR1ZGUsCiAgICByYWRpdXMgPSA0LAogICAgb3BhY2l0eSA9IDEsCiAgICBmaWxsT3BhY2l0eSA9IDEsCiAgICB3ZWlnaHQgPSAxCiAgKQpgYGAKCjxici8+CgojIyMgMi4gQ2FsY3VsYXRpbmcgUHJlY2lwaXRhdGlvbiBNZWFucwoKU2VlaW5nIHRoZSBsb2NhdGlvbnMgb2YgZWFjaCBtb25pdG9yIHN0YXRpb24gb25seSB0ZWxscyBoYWxmIHRoZSBzdG9yeS4gSXQgd291bGQgYmUgaW50ZXJlc3RpbmcgdG8gZmluZGluZyBvdXQgaWYgdGhlcmUgYXJlIHRyZW5kcyBpbiBwcmVjaXBpdGF0aW9uIGFtb3VudHMgYWNyb3NzIHRoZSBzdGF0ZS4gU2luY2Ugd2UgaGF2ZSB0aGUgcHJlY2lwaXRhdGlvbiBkYXRhIGZvciBlYWNoIG1vbml0b3Igc3RhdGlvbiwgd2UgY2FuIGZpbmQgdGhlIGF2ZXJhZ2UgaG91cmx5IHByZWNpcGl0YXRpb24gb3ZlciB0aGUgeWVhcnMgdGhlIGRhdGEgd2FzIGNvbGxlY3RlZC4gVGhlbiB3ZSBjYW4gY29sb3IgZWFjaCBtYXJrZXIgYmFzZWQgb24gdGhpcyBhdmVyYWdlIHRvIGhlbHAgdXMgdmlzdWFsbHkgY29tcGFyZSB0aGUgdGhlIHByZWNpcGl0YXRpb24gYXJvdW5kIHRoZSBzdGF0ZS4KCkxldCdzIHN0YXJ0IGJ5IHVwZGF0aW5nIG91ciBkYXRhIGZyYW1lLCAqcHJlY2lwLmRldGFpbHMuZGYqLCB3aXRoIHRoZSBtZWFuIHByZWNpcGl0YXRpb24gZm9yIGVhY2ggc3RhdGlvbi4gSGVyZSBpcyBhIHJlbWluZGVyIG9mIHdoYXQgdGhlIGRhdGEgZnJhbWUgbG9va3MgbGlrZToKCmBgYHtyIGVjaG89RkFMU0V9CnByZWNpcC5kZXRhaWxzLmRmCmBgYAoKSW4gdGhlIGNvZGUgY2h1bmsgbGFiZWxlZCAqY2FsY3VsYXRlX3ByZWNpcGl0YWlvbl9tZWFucyosIGxpbmUgODcsIHdlIGNhbGN1bGF0ZSB0aGUgbWVhbiBvZiB0aGUgcHJlY2lwaXRhdGlvbiB2YWx1ZXMgaGVsZCBpbiB0aGUgKmRhdGEqIGNvbHVtbiBhbmQgc3RvcmUgdGhlIHZhbHVlcyBiYWNrIGludG8gb3VyIGRhdGEgZnJhbWUgaW4gYSBjb2x1bW4gbmFtZWQgKm1lYW4qLiBUaGUgdXBkYXRlZCBkYXRhIGZyYW1lIGlzIHNob3duIGJlbG93LgoKCmBgYHtyIGNhbGN1bGF0ZV9wcmVjaXBpdGFpb25fbWVhbnN9CnByZWNpcC5kZXRhaWxzLmRmICU8PiUKICBncm91cF9ieShpZCkgJT4lCiAgbXV0YXRlKG1lYW4gPSBtZWFuKGRhdGFbWzFdXVsyXSRQcmVjaXBpdGF0aW9uKSkgJT4lCiAgdW5ncm91cCgpCgpwcmVjaXAuZGV0YWlscy5kZgpgYGAKCjxici8+CgojIyMjIyBZb3VyIFR1cm46IENhbGN1bGF0ZSB0aGUgTWVhbnMKRm9yIHRoZSBjb2RlIGNodW5rIGxhYmVsZWQgKmNhbGN1bGF0ZV9wcmVjaXBpdGF0aW9uX21lYW5zKiwgcHJlc3MgdGhlICFbUnVuIEJ1dHRvbi5dKGltYWdlcy9ydW5fY3VycmVudF9jb2RlX2J1dHRvbi5wbmcpIGJ1dHRvbiB0byBydW4gdGhlIGNvZGUgY2h1bmsgYW5kIHVwZGF0ZSB0aGUgZGF0YSBmcmFtZS4gVGhlcmUgaXMgbm8gb3V0cHV0IGZyb20gdGhpcyBjb2RlIGNodW5rLgoKPGJyLz4KCkEgY29udmVuaWVudCB3YXkgb2YgZGlzcGxheWluZyB0aGUgbWVhbiBwcmVjaXBpdGF0aW9uIGRhdGEgb24gdGhlIG1hcCBpcyB0byBjb2xvciB0aGUgbWFya2VycyBiYXNlZCBvbiBhIHJhbmdlIG9mIHByZWNpcGl0YXRpb24gdmFsdWVzLiBUaGlzIGFsbG93cyB1c2VycyB0byB2aXN1YWxseSBpbnNwZWN0IHRoZSBtYXAgYW5kIGVzdGltYXRlIHdoaWNoIHN0YXRpb25zIG1heSBoYXZlIGEgaGlnaGVyIG9yIGxvd2VyIG1lYW4gcHJlY2lwaXRhdGlvbi4gTGV0J3MgdXNlIHRoZSAqY29sb3JCaW4oKSogZnVuY3Rpb24gdG8gZ3JvdXAgdGhlIG1lYW4gdmFsdWVzIGludG8gZml2ZSBlcXVhbCBzaXplZCBiaW5zIGFuZCBhc3NpZ24gYSBjb2xvciB0byBlYWNoIGJpbi4gVGhlICpjb2xvckJpbigpKiBmdW5jdGlvbiBhY2NlcHRzIGEgY29sb3IgcGFsZXR0ZSwgYSBsaXN0IG9mIHZhbHVlcywgYW5kIHRoZSBudW1iZXIgb2YgYmlucyB0byBncm91cCB2YWx1ZXMgaW50by4gSXQgcmV0dXJucyBhIGZ1bmN0aW9uLCB0aGF0IHdlIHdpbGwgc3RvcmUgaW4gdGhlIHZhcmlhYmxlICpxcGFsKiwgdGhhdCBjYW4gYmUgY2FsbGVkIHRvIHF1ZXJ5IHRoZSBjb2xvciBiaW4gdGhhdCBhIHZhbHVlIGZhbGxzIGludG8uCgpGb3IgZXhhbXBsZSwgaW4gdGhlIGNvZGUgYmVsb3csIHdlIGNyZWF0ZSBhIHF1ZXJ5YWJsZSBwYWxldHRlLCBuYW1lZCAqcXBhbCosIGJ5IHNwZWNpZnlpbmcgYSBjb2xvciBwYWxldHRlIChgYGBwYWxldHRlID0gIkJsdWVzImBgYCksIHRoZSBkb21haW4gb3IgcmFuZ2Ugb2Ygb3VyIHZhbHVlcyAoYSByYW5kb20gdW5pZm9ybSBkaXN0cmlidXRpb24gb2YgMTAgbnVtYmVycyBiZXR3ZWVuIDAgYW5kIDEpLCBhbmQgdGhlIG51bWJlciBvZiBiaW5zIHdlIHdhbnQgdGhlIHZhbHVlcyB0byBmYWxsIHdpdGhpbiAoYGBgbmJpbnMgPSA1YGBgKToKCmBgYHtyIHBhbGV0dGVfYmlubmluZ19leGFtcGxlfQpwYWxldHRlID0gIkJsdWVzIgp2YWx1ZXMgPSBydW5pZigxMCxtaW49MCxtYXg9MSkKbmJpbnMgPSA1CgpxcGFsID0gY29sb3JCaW4ocGFsZXR0ZSx2YWx1ZXMsbmJpbnMpCmBgYAoKQWJvdmUsIHdlIHVzZWQgcmFuZG9tIG51bWJlcnMgZm9yIG91ciAqdmFsdWVzKiB2YXJpYWJsZS4gTGV0J3Mgc2VlIHdoYXQgY29sb3IgYmlucyB0aGV5IGVuZCB1cCBmYWxsaW5nIGludG86CgpgYGB7ciAsIGVjaG89RkFMU0UsIHJlc3VsdHM9ImhvbGQifQoKI2ZvciAodmFsdWUgaW4gc29ydCh2YWx1ZXMpKSB7CiMgIGFkZENvbG9yU3dhdGNoKHFwYWwodmFsdWUpLHZhbHVlKQojfQoKdmFsdWVzIDwtIHNvcnQodmFsdWVzKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1sxXSksdmFsdWVzWzFdKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1syXSksdmFsdWVzWzJdKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1szXSksdmFsdWVzWzNdKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1s0XSksdmFsdWVzWzRdKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1s1XSksdmFsdWVzWzVdKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1s2XSksdmFsdWVzWzZdKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1s3XSksdmFsdWVzWzddKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1s4XSksdmFsdWVzWzhdKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1s5XSksdmFsdWVzWzldKQphZGRDb2xvclN3YXRjaChxcGFsKHZhbHVlc1sxMF0pLHZhbHVlc1sxMF0pCmBgYAoKPGJyLz4KCiMjIyMjIFlvdXIgVHVybjogQ3JlYXRlIGEgUXVlcnlhYmxlIFBhbGV0dGUKTm93IGl0J3MgeW91ciB0dXJuIHRvIGNyZWF0ZSBhIHF1ZXJ5YWJsZSBwYWxldHRlIGZvciBvdXIgbWFwIG1hcmtlcnMuIEluIHRoZSBjb2RlIGNodW5rIGxhYmVsZWQgKmNhbGN1bGF0ZV9jb2xvcl9mcm9tX21lYW4qLCBsaW5lIDk3LCB1c2UgdGhlIGNvbG9yQmluKCkgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgYSBwYWxldHRlIGZvciBvdXIgcHJlY2lwaXRhdGlvbiBtZWFucy4gQmUgc3VyZSB0byBmaWxsIGluIHRoZXNlIHRocmVlIGl0ZW1zOgoKMS4gQ2hvb3NlIGEgY29sb3IgcGFsZXR0ZSAoTGluZSAxMDUpCjIuIFNwZWNpZnkgdGhlIGRvbWFpbiBmb3Igb3VyIHByZWNpcGljYXRpb24gbWVhbiB2YWx1ZXMgKExpbmUgMTE2KQozLiBTZXQgdGhlIG51bWJlciBvZiBiaW5zIHRoZSB2YWx1ZXMgY2FuIGZhbGwgaW50byAoTGluZSAxMjEpCgpZb3VyIGNvZGUgc2hvdWxkIGxvb2sgc29tZXRoaW5nIGxpa2UgdGhpczoKCmBgYHtyIGNhbGN1bGF0ZV9jb2xvcl9mcm9tX21lYW59CiMgWU9VUiBUVVJOOgojIE9uIHRoZSBuZXh0IGxpbmUsIHRyeSBzZXR0aW5nIHBhbGV0dGUgdG8gb25lIG9mIHRoZSBmb2xsb3dpbmc6CiMgICAiUmRZbEJ1IgojICAgIkJsdWVzIgojICAgIllsT3JSZCIKIyBjaGVjayBvdXQgaHR0cDovL2NvbG9yYnJld2VyMi5vcmcvIGZvciBtb3JlIHBhbGV0dGVzCiMgSSBsaWtlICJZbE9yUmQiCnBhbGV0dGUgPSAiWWxPclJkIgoKIyBZT1VSIFRVUk46CiMgU2V0IHRoZSBkb21haW4gb2YgdmFsdWVzIHRvIHRoZSBtZWFuIGNvbHVtbiBpbiBvdXIgZGF0YSBmcmFtZToKIyAgIHByZWNpcC5kZXRhaWxzLmRmJG1lYW4KdmFsdWVzID0gcHJlY2lwLmRldGFpbHMuZGYkbWVhbgoKIyBZT1VSIFRVUk46CiMgQ2hvb3NlIHRoZSBudW1iZXIgb2YgYmlucy4gQSBnb29kIGNob2ljZSBpcyBhbiBpbnRlZ2VyIGJldHdlZW4gMiBhbmQgNwojIEkgbGlrZSA1Cm5iaW5zID0gNQoKIyBDcmVhdGUgYSBwYWxldHRlIHdlIGNhbiBxdWVyeSBmb3Igd2hpY2ggYmluIGEgdmFsdWUgZmFsbHMgaW50by4KcXBhbCA9IGNvbG9yQmluKHBhbGV0dGUsdmFsdWVzLG5iaW5zKQoKIyBBZGQgYSBjb2x1bW4gbmFtZWQgJ2NvbG9yJyB0byBvdXIgZGF0YSBmcmFtZS4gSXQgaG9sZHMKIyB0aGUgYmluIGVhY2ggc3RhdGlvbidzIG1lYW4gcHJlY2lwaXRhdGlvbiBmYWxscyBpbnRvLgpwcmVjaXAuZGV0YWlscy5kZiAlPD4lCiAgbXV0YXRlKGNvbG9yID0gcXBhbChtZWFuKSkKYGBgCgoqKldoZW4geW91IGhhdmUgY29tcGxldGVkIHVwZGF0aW5nIHRoZSBjb2RlIGNodW5rLCBydW4gaXQgYnkgcHJlc3NpbmcgdGhlICFbUnVuIEJ1dHRvbi5dKGltYWdlcy9ydW5fY3VycmVudF9jb2RlX2J1dHRvbi5wbmcpIGJ1dHRvbiBpbiB0aGUgY29kZSBjaHVuayBjb250cm9scy4qKgoKPGJyLz4KCkdyZWF0ISBPdXIgdXBkYXRlZCBkYXRhIGZyYW1lIG5vdyBoYXMgYSBjb2x1bW4gbmFtZWQgKmNvbG9yKiwgd2hpY2ggZGVzY3JpYmVzIHdoaWNoIGJpbiB0aGUgbWVhbiBwcmVjaXBpdGF0aW9uIHZhbHVlIGZhbGxzIGludG8uIExldCdzIGhhdmUgYSBsb29rOgoKYGBge3Igc2hvd19jb2xvcl9jb2x1bW4sIGVjaG89RkFMU0V9CiMgcHJpbnQgb3V0IHRoZSBkYXRhIGZyYW1lCnByZWNpcC5kZXRhaWxzLmRmCmBgYAoKVGhlIG5leHQgdGFzayBpcyB0byB1cGRhdGUgb3VyIG1hcCB0byBzaG93IG91ciBjdXN0b20gY29sb3IgZm9yIHRoZSBtYXJrZXIgaW5zdGVhZCBvZiB0aGUgZGVmYXVsdCBibHVlIGNvbG9yLiBJbiB0aGUgY29kZSBjaHVuayBsYWJlbGVkICpwbG90X3N0YXRpb25fbG9jYXRpb25zX3dpdGhfY29sb3JzKiwgbGluZSAxMzUsIHdlIGNyZWF0ZSBhIG1hcCB1c2luZyB0aGUgYGBgbGVhZmxldCgpYGBgIGZ1bmN0aW9uIGFuZCB0aGVuIHVzZSB0aGUgYGBgYWRkQ2lyY2xlTWFya2VycygpYGBgIGZ1bmN0aW9uIHRvIHBsYWNlIGNpcmNsZSBtYXJrZXJzIG9uIHRoZSBtYXAgYXQgdGhlIGxvY2F0aW9ucyBvZiB0aGUgbW9uaXRvciBzdGF0aW9ucy4gV2UgbmVlZCB0byB1cGRhdGUgdGhpcyBtYXAgZGVjbGFyYXRpb24gdG8gdXNlIHRoZSB2YWx1ZXMgd2Ugc3RvcmVkIGluIHRoZSAqY29sb3IqIGNvbHVtbiBvZiBvdXIgZGF0YSBmcmFtZS4KCjxici8+CgojIyMjIyBZb3VyIFR1cm46IENvbG9yIHRoZSBNYXAgTWFya2VycwpBZGQgdGhlIGZvbGxvd2luZyBhcmd1bWVudCB0byB0aGUgYGBgYWRkQ2lyY2xlTWFya2VycygpYGBgIGZ1bmN0aW9uIHRvIHRlbGwgdGhlIG1hcCB0byBjb2xvciB0aGUgbWFya2VycyB1c2luZyB0aGUgKmNvbG9yKiBjb2x1bW4gd2UgZ2VuZXJhdGVkIGVhcmxpZXIgZnJvbSBvdXIgY3VzdG9tIGNvbG9yIHBhbGV0dGUgYW5kIGJpbnM6CgpgYGBjb2xvciA9IH5jb2xvcmBgYAoKQWZ0ZXIgeW91IGhhdmUgbWFkZSB0aGUgY2hhbmdlLCB5b3VyIGNvZGUgY2h1bmsgc2hvdWxkIGxvb2sgbGlrZSB0aGlzOgoKYGBge3IgcGxvdF9zdGF0aW9uX2xvY2F0aW9uc193aXRoX2NvbG9ycywgZXZhbD1GQUxTRX0KbWFwIDwtIGxlYWZsZXQocHJlY2lwLmRldGFpbHMuZGYgJT4lIHNlbGVjdCgtZGF0YSkpICU+JQogICAgICAgIGFkZFRpbGVzKCkKCm1hcCAlPiUKICAjIGNyZWF0ZSB0aGUgYmlubmVkIGNvbG9yIG1hcmtlcgogIGFkZENpcmNsZU1hcmtlcnMoCiAgICBsYWJlbCA9IH5uYW1lLAogICAgbG5nID0gfmxvbmdpdHVkZSwKICAgIGxhdCA9IH5sYXRpdHVkZSwKICAgIHJhZGl1cyA9IDQsCiAgICBvcGFjaXR5ID0gMSwKICAgIGZpbGxPcGFjaXR5ID0gMSwKICAgICMgWU9VUiBUVVJOOgogICAgIyBPbiB0aGUgbmV4dCBsaW5lLCBhZGQgdGhlIGFyZ3VtZW50OiBjb2xvciA9IH5jb2xvciwKICAgIGNvbG9yID0gfmNvbG9yLAogICAgd2VpZ2h0ID0gMQogICkKYGBgCgo8YnIvPgoKIyMjIyMgWW91ciBUdXJuOiBHZW5lcmF0ZSBhbiBVcGRhdGVkIE1hcApSdW4gdGhlIGNvZGUgY2h1bmssIHVzaW5nIHRoZSAhW1J1biBCdXR0b24uXShpbWFnZXMvcnVuX2N1cnJlbnRfY29kZV9idXR0b24ucG5nKSBidXR0b24gaW4gdGhlIHVwcGVyIHJpZ2h0IGNvcm5lciBvZiB0aGUgY2h1bmssIHRvIHNlZSB3aGF0IHRoZSB1cGRhdGVkIG1hcCBsb29rcyBsaWtlLiBUaGUgbWFya2VycyBzaG91bGQgbm93IGJlIGEgcmFuZ2Ugb2YgY29sb3JzLCBzaW1pbGFyIHRvIHRoaXMgb25lOgpgYGB7ciBzaG93X3VwZGF0ZWRfbWFwX3dpdGhfY29sb3JfYmlubmVkX21hcmtlcnMsIGVjaG89RkFMU0V9Cm1hcCA8LSBsZWFmbGV0KHByZWNpcC5kZXRhaWxzLmRmICU+JSBzZWxlY3QoLWRhdGEpKSAlPiUKICAgICAgICBhZGRUaWxlcygpCgptYXAgJT4lCiAgIyBjcmVhdGUgdGhlIGJpbm5lZCBjb2xvciBtYXJrZXIKICBhZGRDaXJjbGVNYXJrZXJzKAogICAgbGFiZWwgPSB+bmFtZSwKICAgIGxuZyA9IH5sb25naXR1ZGUsCiAgICBsYXQgPSB+bGF0aXR1ZGUsCiAgICByYWRpdXMgPSA0LAogICAgb3BhY2l0eSA9IDEsCiAgICBmaWxsT3BhY2l0eSA9IDEsCiAgICAjIFlPVVIgVFVSTjoKICAgICMgT24gdGhlIG5leHQgbGluZSwgYWRkIHRoZSBhcmd1bWVudDogY29sb3IgPSB+Y29sb3IsCiAgICBjb2xvciA9IH5jb2xvciwKICAgIHdlaWdodCA9IDEKICApCmBgYAoKPGJyLz4KCiMjIyAzLiBBZGQgTWFya2VyIEJvcmRlcnMKClRoZSBtYXJrZXJzIG5vdyBzaG93IGFub3RoZXIgZGltZW5zaW9uIG9mIGluZm9ybWF0aW9uIGZyb20gb3VyIGRhdGEgZnJhbWUsIHRoZSBiaW5uZWQgbWVhbiBwcmVjaXBpdGF0aW9uLiBJZiB5b3UgdXNlZCB0aGUgKidZbE9yUmQnKiBwYWxldHRlLCB5b3UgbWF5IG5vdGljZSB0aGF0IHNvbWUgb2YgdGhlIG1hcmtlcnMgYXJlIGEgbGl0dGxlIGhhcmQgdG8gc2VlLiBGb3IgZXhhbXBsZSwgdGhlIGxpZ2h0IHllbGxvdyBtYXJrZXIgaW4gdGhlIG5vcnRoIGNlbnRyYWwgcGFydCBvZiBJbmRpYW5hLCBuZWFyIHRoZSBjaXR5IG9mIFNvdXRoIEJlbmQsIGFsbW9zdCBibGVuZHMgaW4gd2l0aCBiYXNlIG1hcCBiYWNrZ3JvdW5kLiBPbmUgZWFzeSB3YXkgdG8gc29sdmUgdGhpcyBwcm9ibGVtIGlzIHRvIHBsYWNlIGEgc2xpZ2h0bHkgbGFyZ2VyIGJsYWNrIG1hcmtlciBiZWhpbmQgdGhlIG1hcmtlciBkaXNwbGF5aW5nIG91ciBiaW4gY29sb3IuIFRoaXMgd2lsbCBnaXZlIHRoZSBlZmZlY3Qgb2YgdGhlIG1hcmtlciBoYXZpbmcgYSBib3JkZXIsIGhlbHBpbmcgdG8gZGlzdGluZ3Vpc2ggaXQgZnJvbSBvdGhlciBhcnRpZmFjdHMgb24gdGhlIG1hcC4KCkluIHRoZSBjb2RlIGNodW5rIGxhYmVsZWQgKmFkZF9ibGFja19iYWNrZ3JvdW5kX21hcmtlciosIGxpbmUgMTYxLCB3ZSBjcmVhdGUgdHdvIHR5cGVzIG9mIG1hcmtlcnMgb24gdGhlIG1hcC4gVGhlIGZpcnN0IG1hcmtlciBpcyBhIGJsYWNrIG1hcmtlciB0aGF0IHdpbGwgYWN0IGFzIGEgYm9yZGVyLiBUaGUgc2Vjb25kIG1hcmtlciBzaXRzIG9uIHRvcCBvZiB0aGUgYmxhY2sgbWFya2VyIGFuZCBzaG93cyB0aGUgYmlubmVkIGNvbG9yIGZvciB0aGUgbWVhbiBwcmVjaXBpdGF0aW9uIHZhbHVlLgoKPGJyLz4KCiMjIyMjIFlvdXIgVHVybjogQ3JlYXRlIEJhY2tncm91bmQgTWFya2VycwpNb2RpZnkgdGhlIGZpcnN0IG1hcmtlciBpbiB0aGUgY29kZSBjaHVuayB0bzoKCjEuIFNldCAqYWRkQ2lyY2xlTWFya2VycygpKidzIGNvbG9yIGFyZ3VtZW50IHRvICIjMDAwMDAwIiwgdGhlIGhleGFkZWNpbWFsIHZhbHVlIGZvciB0aGUgSFRNTCBjb2xvciByZXByZXNlbnRpbmcgYmxhY2suCjIuIFNldCB0aGUgbGluZSB3aWR0aCAod2VpZ2h0KSB0byAzLCBhIHZhbHVlIHNsaWdodGx5IGxhcmdlciB0aGFuIHRoYXQgb2YgdGhlIHNlY29uZCBtYXJrZXIuCgpBZnRlciB5b3UgaGF2ZSBtYWRlIHRoZSBjaGFuZ2UsIHRoZSBjb2RlIGNodW5rIHNob3VsZCBsb29rIHNvbWV0aGluZyBsaWtlIHRoaXM6CgpgYGB7ciBhZGRfYmxhY2tfYmFja2dyb3VuZF9tYXJrZXJ9Cm1hcCAlPD4lCiAgIyBjcmVhdGUgdGhlIGJsYWNrIGJvcmRlciBtYXJrZXIKICBhZGRDaXJjbGVNYXJrZXJzKAogICAgbG5nID0gfmxvbmdpdHVkZSwKICAgIGxhdCA9IH5sYXRpdHVkZSwKICAgIHJhZGl1cyA9IDQsCiAgICBvcGFjaXR5PTEsCiAgICBmaWxsT3BhY2l0eSA9IDAsCiAgICAjIFlPVVIgVFVSTjoKICAgICMgMS4gU2V0IHRoZSBjb2xvciBhcmd1bWVudCB0byAiIzAwMDAwMCIKICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgIyBZT1VSIFRVUk46CiAgICAjIDIuIFNldCB0aGUgd2VpZ2h0IGFyZ3VtZW50IHRvIDMKICAgIHdlaWdodCA9IDMKICApICU+JQogICMgY3JlYXRlIHRoZSBiaW4gY29sb3IgbWFya2VyCiAgYWRkQ2lyY2xlTWFya2VycygKICAgIGxhYmVsID0gfm5hbWUsCiAgICBsbmcgPSB+bG9uZ2l0dWRlLAogICAgbGF0ID0gfmxhdGl0dWRlLAogICAgcmFkaXVzID0gNCwKICAgIG9wYWNpdHkgPSAxLAogICAgZmlsbE9wYWNpdHkgPSAxLAogICAgY29sb3IgPSB+Y29sb3IsCiAgICB3ZWlnaHQgPSAxCiAgKQpgYGAKCjxici8+CgojIyMjIyBZb3VyIFR1cm46IFZpZXcgTWFwIHdpdGggVXBkYXRlZCBNYXJrZXJzCk5vdyBydW4gdGhlIGNvZGUgY2h1bmsgdG8gY29uZmlybSB0aGF0IHRoZSB1cGRhdGVkIG1hcCBzaG93cyBhIGJvcmRlciBhcm91bmQgdGhlIG1hcmtlcnMuIFByZXNzIHRoZSAhW1J1biBCdXR0b24uXShpbWFnZXMvcnVuX2N1cnJlbnRfY29kZV9idXR0b24ucG5nKSBidXR0b24gaW4gdGhlIHVwcGVyIHJpZ2h0IGNvcm5lciBvZiB0aGUgY2h1bmsgdG8gZXhlY3V0ZSB0aGUgY29kZS4KCmBgYHtyIHNob3dfbWFwX3dpdGhfYm9yZGVyX2Fyb3VuZF9tYXJrZXJzLCBlY2hvPUZBTFNFfQptYXAKYGBgCgo8YnIvPgoKIyMjIDQuIEFkZCBhIExlZ2VuZCB0byB0aGUgTWFwCgpUaGUgYmxhY2sgYm9yZGVyIGFyb3VuZCB0aGUgY29sb3JlZCBtYXJrZXIgaGVscHMgdXNlcnMgZGlzdGluZ3Vpc2ggdGhlbSBmcm9tIGEgc2ltaWxhcmx5IGNvbG9yZWQgYmFja2dyb3VuZC4gVGhlIG1hcCBpcyBtaXNzaW5nIG9uZSBtb3JlIGl0ZW0uIE5vIG1hcCBpcyBjb21wbGV0ZSB3aXRob3V0IGEgbGVnZW5kIGFuZCBpdCBpcyBlc3BlY2lhbGx5IGltcG9ydGFudCBpbiB0aGlzIGNhc2UuIEhhdmluZyB0aGUgY29sb3JlZCBtYXJrZXJzIG9uIHRoZSBtYXAgbG9va3MgbmljZSwgYnV0IHdpdGhvdXQgdGhlIGxlZ2VuZCwgdXNlcnMgZG9uJ3Qga25vdyB3aGF0IHRoZSBjb2xvcnMgbWVhbi4KCldlJ2xsIHVzZSB0aGUgYGBgYWRkTGVnZW5kKClgYGAgZnVuY3Rpb24gdG8gYWRkIGEgbGVnZW5kIHRvIHRoZSBtYXAuIEluIHRoZSBjb2RlIGNodW5rIGxhYmVsZWQgKmFkZF9sZWdlbmRfdG9fbWFwKiwgbGluZSAxOTQsIHRoZSBgYGBhZGRMZWdlbmQoKWBgYCBmdW5jdGlvbiBhY2NlcHRzIGEgbnVtYmVyIG9mIHBhcmFtZXRlcnMgdGVsbGluZyB0aGUgbWFwIGhvdyB0byBjb25maWd1cmUgdGhlIGxlZ2VuZCwgbGlrZSB0aXRsZSwgcGxhY2VtZW50LCBhbmQgYmFja2dyb3VuZCBvcGFjaXR5LgoKPGJyLz4KCiMjIyMjIFlvdXIgVHVybjogU2V0dXAgTWFwIExlZ2VuZApBZGp1c3QgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzOgoKMS4gU2V0IHRoZSAqcGFsKiBhcmd1bWVudCB0byAqcXBhbCosIHRoZSBuYW1lIG9mIG91ciBjdXN0b20gYmlubmVkIGNvbG9yIHBhbGV0dGUgZnVuY3Rpb24uCjIuIFNldCB0aGUgKnZhbHVlcyogYXJndW1lbnQgdG8gKn5tZWFuKiwgdGhlIGNvbHVtbiBpbiBvdXIgZGF0YSBmcmFtZSB0aGF0IGhvbGRzIHRoZSBjYWxjdWxhdGVkIG1lYW4gcHJlY2lwaXRhdGlvbiB2YWx1ZXMuCgpBZnRlciBtYWtpbmcgdGhlIGFkanVzdG1lbnRzLCB0aGUgY29kZSBjaHVuayBzaG91bGQgbG9vayBsaWtlIHRoaXM6CgpgYGB7cn0KbWFwICU8PiUgCiAgYWRkTGVnZW5kKAogICAgImJvdHRvbXJpZ2h0IiwKICAgIHRpdGxlID0gIjxjZW50ZXI+TWVhbiBIb3VybHk8YnI+CiAgICAgICAgICAgICBQcmVjaXBpdGF0aW9uPGJyLz4KICAgICAgICAgICAgIDxzbWFsbD4KICAgICAgICAgICAgICAgZm9yIGhvdXJzIHdpdGg8YnIvPgogICAgICAgICAgICAgICBtZWFzdXJhYmxlPGJyLz4KICAgICAgICAgICAgICAgcHJlY2lwaXRhdGlvbgogICAgICAgICAgICAgPC9zbWFsbD48L2NlbnRlcj4iLAogICAgb3BhY2l0eSA9IDEsCiAgICBsYWJGb3JtYXQgPSBsYWJlbEZvcm1hdChzdWZmaXg9ImluIiksCiAgICAjIFlPVVIgVFVSTjoKICAgICMgU2V0IHRoZSBwYWwgYXJndW1lbnQgdG8gb3VyIGN1c3RvbSBiaW5uZWQgcGFsZXR0ZSBmdW5jdGlvbiwgcXBhbAogICAgcGFsID0gcXBhbCwKICAgICMgWU9VUiBUVVJOOgogICAgIyBTZXQgdGhlIHZhbHVlcyBhcmd1bWVudCB0byB0aGUgbWVhbiBwcmVjaXBpdGF0aW9uIHZhbHVlcywgfm1lYW4KICAgIHZhbHVlcyA9IH5tZWFuCiAgKQpgYGAKCjxici8+CgojIyMjIyBZb3VyIFR1cm46IFZpZXcgTWFwIHdpdGggTGVnZW5kCkV4ZWN1dGUgdGhlIGNvZGUgaW4gdGhlIGNvZGUgY2h1bmsgdXNpbmcgdGhlICFbUnVuIEJ1dHRvbi5dKGltYWdlcy9ydW5fY3VycmVudF9jb2RlX2J1dHRvbi5wbmcpIGJ1dHRvbiBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyIG9mIHRoZSBjaHVuay4gRG8geW91IHNlZSBvdXIgbmV3IGxlZ2VuZCBvbiB0aGUgbWFwPyBJdCBzaG91bGQgc2hvdyB3aGF0IHZhbHVlcyB0aGUgbWFya2VyIGNvbG9ycyBjb3JyZXNwb25kIHRvLgoKYGBge3IsIGVjaG89RkFMU0V9Cm1hcApgYGAKCjxici8+CgojIyMgNS4gUHV0dGluZyBpdCBhbGwgVG9nZXRoZXIKCllvdSBtYXkgbm90IGhhdmUgbm90aWNlZCwgYnV0IHRoZSBmaWxlIHdlIGhhdmUgYmVlbiBlZGl0aW5nIGlzIGFjdHVhbGx5IGFuIFJNYXJrZG93biBkb2N1bWVudC4gV2UgaGF2ZSBiZWVuIG1peGluZyBvdXIgUiBjb2RlIHdpdGggTWFya2Rvd24gd2lraSBzeW50YXggYW5kIGV4ZWN1dGluZyB0aGUgY29kZSBjaHVua3MganVzdCBhcyB3ZSB3b3VsZCBpbiBhIGxpdGVyYXRlIGNvbXB1dGluZyBzdHlsZSBOb3RlYm9vay4KCklmIHlvdSBnbyBiYWNrIHRocm91Z2ggdGhlIGNvZGUgeW91IG1heSBub3RpY2Ugc3ludGF4IGluIGJldHdlZW4gdGhlIGNvZGUgY2h1bmtzIGxpa2UgdGhpczoKCmBgYApSb3cKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIFN0ZXAgIzEgLSBQcmVjaXBpdGF0aW9uIE1vbml0b3IgU3RhdGlvbnMKYGBgCgphbmQgbGlrZSB0aGlzOgoKYGBgCiMjIyBTdGVwICM0IC0gQWRkIGEgbGVnZW5kIHRvIHRoZSBtYXAKYGBgCgpUaGVzZSBhcmUgUk1hcmtkb3duIHdpa2kgc3ludGF4IHRoYXQgZ2l2ZSBoaW50cyBhYm91dCBob3cgdG8gZm9ybWF0IHRoZSBmaWxlIHdoZW4gcmVuZGVyZWQgYXMgYSB3ZWIgcGFnZS4gQXQgdGhlIHRvcCBvZiB0aGUgZmlsZSwgZXhpc3RzIHRoaXMgWUFNTCBkZWNsYXJhdGlvbjoKCmBgYAotLS0KdGl0bGU6IEV4cGxvcmluZyBQcmVjaXBpdGF0aW9uIEFjcm9zcyBJbmRpYW5hCm91dHB1dDoKICBmbGV4ZGFzaGJvYXJkOjpmbGV4X2Rhc2hib2FyZDoKICAgIG9yaWVudGF0aW9uOiByb3dzCi0tLQpgYGAKCkFsbCBSTWFya2Rvd24gZmlsZXMgaGF2ZSBhIFlBTUwgZGVjbGFyYXRpb24gYXQgdGhlIHRvcC4gVGhpcyBvbmUgc3RhdGVzIHRoYXQgdGhlIGZpbGUgc2hvdWxkIGJlIHJlbmRlcmVkIGFzIGEgRmxleERhc2hib2FyZCwgd2hpY2ggaXMgb25lIG9mIHRoZSBSTWFya2Rvd24gdGVtcGxhdGVzIHRoYXQgYWxsb3cgZGV2ZWxvcGVycyB0byBxdWlja2x5IGdlbmVyYXRlIGEgZGFzaGJvYXJkIGZyb20gdGhlIFIgYW5kIE1hcmtkb3duIGNvZGUgaW4gdGhlIGZpbGUuIFRoZXJlIGFyZSBhIG51bWJlciBvZiBkaWZmZXJlbnQgc3R5bGVzIG9mIEZsZXhEYXNoYm9hcmRzIGFuZCB5b3UgY2FuIGxlYXJuIG1vcmUgYWJvdXQgdGhlbSBhdCBodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2ZsZXhkYXNoYm9hcmQvLiAKCk91ciBGbGV4RGFzaGJvYXJkIGNvbnRhaW5zIGEgMngyIGdyaWQgb2YgdGhlIG1hcHMgd2UgaGF2ZSBjcmVhdGVkIHRvZGF5LiBXZSBjYW4gcmVuZGVyIGl0IHRvIEhUTUwgYnkgdXNpbmcgdGhlICpLbml0KiAoIVtLbml0IEJ1dHRvbi5dKGltYWdlcy9rbml0X2J1dHRvbi5wbmcpKSBidXR0b24gbmVhciB0aGUgdG9wIG9mIHRoZSBSU3R1ZGlvIElERS4KCjxici8+CgojIyMjIyBZb3VyIFR1cm46IEdlbmVyYXRlIGFuIEhUTUwgRG9jdW1lbnQKUHJlc3MgdGhlICFbS25pdCBCdXR0b24uXShpbWFnZXMva25pdF9idXR0b24ucG5nKSBidXR0b24sIGp1c3QgYWJvdmUgdGhlIGNvZGUgcGFuZSwgdG8gZ2VuZXJhdGUgYW5kIHZpZXcgb3VyIEhUTUwgZG9jdW1lbnQuIEEgbmV3IHdpbmRvdyBzaG91bGQgcG9wIHVwIHdpdGggYWxsIG9mIHRoZSBtYXBzIHlvdSBnZW5lcmF0ZWQgaW4gdGhpcyBleGVyY2lzZS4KCjxkaXYgY2xhc3M9InR1dGltZyI+CiFbTWFwcyB3ZSBidWlsdCBpbiB0aGlzIHR1dG9yaWFsLl0oaW1hZ2VzL3R1dG9yaWFsX3Jlc3VsdC5wbmcpe3dpZHRoPTcwJX0KPC9kaXY+CgoKPGJyLz4KCiMjIyA2LiBVc2UgdGhlIE1hcCBmb3IgQW5hbHlzaXMKCk5vdyB0aGF0IHdlIGhhdmUgYnVpbHQgYSB3ZWIgcGFnZSB0aGF0IGRpc3BsYXlzIG91ciBzdGF0aW9uIGxvY2F0aW9ucyBvbiBhIG1hcCBhbmQgc2hvd3MgdXMgbWVhbiBob3VybHkgcHJlY2lwaXRhdGlvbiBmb3IgaG91cnMgd2l0aCBtZWFzdXJhYmxlIHByZWNpcGl0YXRpb24sIGxldCdzIHVzZSB0aGF0IG1hcCB0byBsZWFybiBzb21ldGhpbmcgbmV3IQoKVmlzdWFsbHkgaW5zcGVjdCB0aGUgbWFwLgoKMS4gSXMgdGhlcmUgYSB0cmVuZCBpbiB0aGUgcmVjb3JkZWQgbWVhbiBob3VybHkgcHJlY2lwaWNhdGlvbiBhY3Jvc3MgdGhlIHN0YXRlIG9mIEluZGlhbmE/CjIuIENhbiB5b3UgdGVsbCB3aGljaCBzdGF0aW9uIGxvb2tzIGxpa2UgaXQgaGFzIHRoZSBoaWdoZXN0IG1lYW4gaG91cmx5IHByZWNpcGl0YXRpb24/CgpXZSBjYW4gdXNlIHRoZSBgYGBmaWx0ZXIoKWBgYCBhbmQgYGBgc2VsZWN0KClgYGAgZnVuY3Rpb25zIHRvIHF1ZXJ5IHRoaXMgaW5mb3JtYXRpb24gZnJvbSB0aGUgZGF0YSBmcmFtZSB0byBjb25maXJtIG91ciBzdXNwaWNpb24uIFRoZSBgYGBmaWx0ZXIoKWBgYCBmdW5jdGlvbiBmaW5kcyB0aGUgcm93IHdoZXJlIHRoZSAqbWVhbiogY29sdW1uIGlzIGVxdWFsIHRvIHRoZSBgYGBtYXgoKWBgYCBvZiBhbGwgdmFsdWVzIGluIHRoZSBjb2x1bW4uIFRoZSBgYGBzZWxlY3QoKWBgYCBmdW5jdGlvbiByZXR1cm5zIHRoZSAqbmFtZSogY29sdW1uIGZvciB0aGF0IHJvdy4KCmBgYHtyIGZpbmRfaGlnaGVzdF9tZWFuX3ByZWNpcH0KaGlnaG1lYW4uc3RhdGlvbi5uYW1lIDwtIHByZWNpcC5kZXRhaWxzLmRmICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIobWVhbiA9PSBtYXgobWVhbikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QobmFtZSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC5bWzFdXQpgYGAKCkRpZCB5b3UgcGljayB0aGUgKmByIGhpZ2htZWFuLnN0YXRpb24ubmFtZWAqIHN0YXRpb24/Cgo8YnIvPgoKIyMjIEV4ZXJjaXNlIENvbXBsZXRlZCEKCkNvbmdyYXR1bGF0aW9ucywgeW91IGhhdmUgY29tcGxldGVkIHRoaXMgZXhlcmNpc2UuIEluIHRoZSBuZXh0IHNlY3Rpb24sIHlvdSB3aWxsIGxlYXJuIG1vcmUgYWJvdXQgcHVibGlzaGluZyBhcHBsaWNhdGlvbnMgbGlrZSB0aGlzIG9uIHRoZSBIVUJ6ZXJvIFBsYXRmb3JtLgo=