This markdown gives you instructions for importing and understanding the PPP data for your mini-memo. There are other background documents and example stories in the Canvas module that you can also review.

Download the data

To load the data into your Global Environment add this line to a code chunk:

    data_url <- "https://github.com/cronkitedata/rstudyguide/blob/master/data/az_ppp_zipcodes.Rda?raw=true"

    load (url ( data_url) )
    

This will create two data frames in your working environment: az_ppp_zip, which is the list of loans, and az_by_zipcode, which has information on the zip codes.

Sources

PPP loans

The original data was published by the SBA here https://sba.app.box.com/s/5myd1nxutoq8wxecx2562baruz774si6 on March 1, 2021. I downloaded and unzipped the PPP portion, and read it into R using a different program.

The SBA has never released a record layout or data dictionary for this data that I can find. I worked on a project over the Christmas break using an earlier version of the data, so I think I understand much of what it contains.

I selected about half of the variables that are included in the original data, and simplified a few as shown below. I also converted all character fields to upper case to ease filtering, and converted the Zip Codes to 5-digits .

This dataset includes all loans that were made to companies in Arizona. A handful (6) of these are going toward projects in other states.

Here are the columns I kept, and what I understand them to mean. Any changes other than those above are indicated in the record layout.

The loan application form . There’s one important thing I don’t know the answer to: There are no rows with a loan statust that suggests that it was forgiven, though we know from reports that more than $100 billion have already been forgiven. There is a “loan status” field in the data, but that doesn’t have anything related to forgiveness, and the “PAID IN FULL” indicator doesn’t add up to nearly enough money. I’m trying to find out what the answer is there, but I wanted to warn you not to use that column until we get some clarity on it.

column name type description
id n A unique identifier supplied by the SBA
date_approved d Date the loan was initially approved
status_date d When the status was reported (NA if unreported)
borrower c Name of the borrower, all upper case
address c Address of the borrower
city c
state c
zip c 5-digit Zip code of the borrower, as reported on the loan
census_zipcode c 5-digit “zip code tabulatioon area” used by the Census bureau*
loan_status c Blank if redacted because of EXEMPTION 4 - VERY unclear what this means!
term n Months to pay back
initial_amt n Initial amount approved by SBA, as reported by the bank.
payroll_amt n Amount used for payroll
nonpayroll_amt n Total amount used for other costs such as utilities, rent, or interest on loans
franchise c Name of a franchisee
business_type c How the business is organized, such as “SOLE PROPRIETOR” or “CORPORATION”
lender c Name of originating lender (not servicing lender)
lender_state c
rural_urban c
business_age c How long the business had been open before the loan -
project_city c City where the money will be used
project_county c County where the money will be used
project_state c State where the county will be used
jobs_reported n Number of jobs “saved” by the loan
naics_code c Standard industry code used in the federal government
naics_sector c Sector of that standard industry code, where it was a valid one
naics_descript c 2017 description of the industry, blank if a previous year’s version used
race c Race of business owner, “UNANSWERED” is 85% of loans. Hispanic is not a race.
ethnicity c “HISPANIC OR LATINO”, “NOT HISPANIC OR LATINO”, “UNKNOWN/NOTSTATED” (85% of loans)
gender c Same with gender - Usually not filled out
veteran c Same with veteran - Usually not filled out
non_profit c “Y” if the borrower is a non-profit organization
  • The census_zipcode is the one that you will use to match against the demographic information.

To get demographic information, we had to use “zip code tabulation areas”, which is what the Census uses. The reason is that Zip Codes are actually postal codes, and refelct post office routes rather than areas. They can also contain post office boxes and special zip codes for large institutions like ASU. I created a new column in this dataset to reflect that Census zip code, which can be used to match against the rest of our demographic information.

Creating it was a two-step process. First, I matched all “ZCTA” data from the Census itself against the original list and kept whatever matched. If they didn’t, I applied the census ZCTA found in the “UDS Mapper” crosswalk, which is a health care coordination consortium created to help administer Obamacare.

One element that isn’t clear is whether the loan was forgiven or not (yet). The borrower has up to two years to request forgiveness, and they can’t even ask until they’ve used all the money.

Zip code data

The zip code data you are getting is a compilation of sources that I created for some work I did for Reveal over the holiday break. (It was preliminary work to get started reporting, and won’t be used in the final story – they were in the process of geocoding every loan so that they had Census Tract information rather than zip codes, which are much better for demographic purposes.)

USPS businesses

There is no good measure of the number of businesses that exist in any small geographic area like zip code or Census Tract. The reason is that most government surveys only include private, for-profit entities with at least 5 employees. About 80 percent of all businesses have NO employees, and a very large proportion of the rest have fewer than 5. The problem is, this loan program was targeted specifically at these small entities!

This means it’s very difficult to estimate the percent of all businesses in a zip code that got loans! The best proxy I could find is from the U.S. Postal Service, which produces a file every quarter that has the number of businesses and residential addresses that can get mail. It excludes PO boxes, and would count as “residential” a business run out of a home, so it’s not exact. But it’s the best we can find.

Demographic information

I obtained the Census data using Social Explorer , which you can access through the ASU library. It makes it relatively easy to obtain cuts of Census products tailored to your needs. I used the 2014-2018 American Community Survey to obtain basic demographic information by Zip Code Tabulation area.

Geographic information

Zip codes don’t have basic geographic elements connected to them! I used the Census TIGER mapping files to attach the county, latitude, longitude, etc. to the zctas using their center points.

Demographic data record layout

column name type Description
zcta c The census zip code (matches to census_zip in the ppp data)
zipcode_city c The name of the post office, from UDS mapper
st_county_fip c A standard code indicating the county that the zip code is in
county_name c The name of that county
metro_name c Metro area name if there is one for that zip code
usps_businesses n # of business addresses estimated by the US Postal Service
tot_pop n Total population (Some are zero)
households n # of households
pct_white_nh n Proportion of White, non-Hispanic population (percent in decimals)
pct_black_nh n Proporation of Black, non-Hispanic
pct_aian_nh n Proportion of American Indian or Alaska Native non-Hispanic
pct_asian_nh n Proportion of Asian non-Hispanic
pct_hispanic n Proportion of Hispanic or Latino population
zcta_ethnic n Ethnicity categorization using Urban Institute’s methodology
white_nh_group n Categorization of the prop.of White non-Hispanic population, using Urban Institute
median_inc_2018 m Median income in 2018 dollars
income_lt25 n Number of households with less than $25,000 annual income
income_150kup n Number of households with $150,000 annual income or more
aggregate_income n Total household income (can be divided by households for average income)
pct_college_grad n Proportion of adults with college degree
pct_kids_droppedout n Proportion of youth 18 and under who dropped out of school
unempl_rate n Average unemployment rate 2014-2018
latitude n The latitude of the center point of the zip code
longitude n The longitude of the center point of the zip code

How to use the demographic data

You can use the demographic information in two ways:

  • To attach information about the area to each individual loan, allowing you to look up businesses that were located in zip codes with specific characteristics.

  • To use with summarised information from the loans to find out, for example, which lenders provided loans in minority areas.

Here are two examples:

Match then filter

Here, we’ll pull out information on the ethnicity of the zip code, and attach it to the individual loan information. Then we can look up businesses that were in certain areas.

First, create a data frame with the information that you want to keep from the demographic file:

az_keep_zip <-
  az_by_zipcode %>%
  select ( zcta, zipcode_city, county_name, usps_businesses: households, zcta_ethnic, white_nh_group, pct_hispanic, pct_white_nh, pct_aian_nh, pct_black_nh, 
           median_inc_2018)

Now join it to the loan data and pick out loans that match a few criteria and select some columns you might want to examine:

az_ppp_zip %>%
  left_join ( az_keep_zip, by=c("census_zip"="zcta")) %>%
  filter ( county_name == "Yuma County", 
           str_detect (zcta_ethnic, "Hispanic"),
           white_nh_group == "0 to 10%") %>%
  select ( borrower, city, census_zip, initial_amt, ethnicity,
          median_inc_2018, zcta_ethnic, pct_hispanic, address
          ) %>%
  arrange ( census_zip, borrower)

Group then match

The opposite strategy can be used to summarize how loans were made to minority and non-minority zip codes. You could use this to find places where very few businesses got loans , or where most of the businesses got loans, in minority neighborhoods. This is a lot more complicated and you have to be careful of data anomolies, but it is also very powerful: It lets you map out the kinds of neighborhoods that got, and didn’t get, loans.

You can look at how much you can do with this approach by looking at one of the metro areas I profiled for the Reveal project.

You could also look at whether the Biden administration is, so far, doing more to serve minority or underserved areas.

Here is a simple example, which looks at the distribution of loans by county, depending on the ethnicity of the zip code.

Step 1: Aggregate (sum) the PPP loans

First, we have to get the number of loans and some other data about each zip code from the PPP loan data. We should also be sure we know how many businesses got loans, not just the number of loans, because we’re going to want to get a rate of participation later on.

ppp_ziptotals <- 
  az_ppp_zip %>%
  group_by ( census_zip ) %>%
  summarise ( loans = n(),
              borrowers = n_distinct ( borrower, zip) , 
              total_amount = sum ( payroll_amt + nonpayroll_amt)
  )

Now we’re going to match them against the zip code information we kept earlier, making sure to keep all of the rows (not just thost that had loans in them). This will drop out any zipcodes that aren’t really in Arizona or are blank in our PPP data. We also have to make the number of loans zero in zip codes that didn’t exist in our PPP loan data.

(This is a “left_join”, which means “keep everything from the first data frame mentioned, and only the things that match from the second one listed.”)

ppp_zip_sums <- 
  az_keep_zip %>%
  left_join ( ppp_ziptotals, by=c("zcta"="census_zip")) %>%
  # we are left with some NA's because not every zip code had any loans
  # There's a shortcut way to do this, but I don't want to make it more confusing than necessary right now.
  mutate ( loans = replace_na (loans, 0), 
           borrowers = replace_na (borrowers, 0), 
           total_amount = replace_na (total_amount, 0)) 

In practice, we’d have to decide what to do in cases in which there were more loans than businesses! In some cases, the Postal Service had no business addresses but there were loans . In others, there were many more loans than there were businesses. You have some choices:

  • Set the % of businesses with loans to 100% if the number of loans was more than the number of unique businesses.

  • Add together the number of businesses and the number of households, to get a stable basis for a comparison. This basically says, “out of all of the entities we know of in this zip code, what portion got loans?” If it’s a business district, that would be high. But it would never be more than 100%!

  • Move up a level of aggregation – look at totals by county and ethnicity, or group the zipcodes together some other way, to summarize the data and paper over the data problems.

  • Don’t worry about it, and pick out some interesting zip codes, such as some with relatively low income or some predominant ethnicity, and then compare their total loan rates with everyone else.

  • Use the anomalies to your advantage – look at those places on a map or a satellite image, and see if they might be good places to center a story!

Here’s an example of aggregating to the county level:

az_ppp_county <- 
   ppp_zip_sums %>%
   group_by (county_name, zcta_ethnic ) %>%
   summarise (across  ( c( usps_businesses, tot_pop, households, loans, borrowers, total_amount) , sum, na.rm=T))
## `summarise()` has grouped output by 'county_name'. You can override using the `.groups` argument.

Now, for each group, calculate the percent of the businesses that were borrowers. Cap it at 100%. I’ll do it in two steps so it’s a little more obvious:

az_ppp_county %>%
  mutate ( pct_borrowed = borrowers / usps_businesses * 100 ) %>%
  # fix it.
  mutate ( pct_borrowed = 
             if_else ( pct_borrowed <= 100, pct_borrowed, 100 )) %>%
  # round it off. 
  mutate (pct_borrowed = round (pct_borrowed, 2))

You can see we get really weird answers for the small counties with few businesses registered with the Postal Service. In this case, we might want to add together the number of households and businesses, and then try it. It’s not awesome, but it at least gives us a reasonable rate of some kind:

az_ppp_county %>%
  mutate ( pct_borrowed = borrowers / (usps_businesses + households) * 100 ) %>%
  # fix it.
  mutate ( pct_borrowed = 
             if_else ( pct_borrowed <= 100, pct_borrowed, 100 )) %>%
  # round it off. 
  mutate (pct_borrowed = round (pct_borrowed, 2))

Let’s do the same thing, but compute some averages by county so we know if it’s different from the total.

az_ppp_county %>%
  mutate ( pct_borrowed = borrowers / (usps_businesses + households) * 100 ) %>%
  # fix it.
  mutate ( pct_borrowed = 
             if_else ( pct_borrowed <= 100, pct_borrowed, 100 )) %>%
  # round it off. 
  mutate (pct_borrowed = round (pct_borrowed, 2), 
          county_pct_borrowed =  round (sum( borrowers) / sum( usps_businesses + households)  * 100, 2)) 

Finally, let’s just pick out some of the numbers and flip them around so that you can compare “spreadsheet” style:

az_ppp_county %>%
  #copied from above
  mutate ( pct_borrowed = borrowers / (usps_businesses + households) * 100 ) %>%
  mutate ( pct_borrowed = 
             if_else ( pct_borrowed <= 100, pct_borrowed, 100 )) %>%
  mutate (pct_borrowed = round (pct_borrowed, 2), 
          county_pct_borrowed =  round (sum( borrowers) / sum( usps_businesses + households)  * 100, 2))  %>%
  #this part is new:
  select ( zcta_ethnic, county_name, county_pct_borrowed, pct_borrowed ) %>%
  filter (str_detect (zcta_ethnic, "01|04|06") ) %>%
  pivot_wider ( names_from = zcta_ethnic, values_from=pct_borrowed)

Because we’ve compared the number of borrowers to a combination of businesses and households, it’s a little hard to describe this answer. But here’s a stab at it:

  In Maricopa County, the predominantly White areas had about 68 percent higher rates of borrowing than predominantly Latino areas, based on the number of businesses and households in each zip code.
LS0tCnRpdGxlOiAiUFBQIGxvYW5zIGluIEFyaXpvbmEiCmF1dGhvcjogIlNhcmFoIENvaGVuIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiB5ZXRpCiAgICBoaWdobGlnaHQ6IGthdGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBkZl9wcmludDogcGFnZWQKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHJtZGZvcm1hdHMpCgprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCgpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKCgpvcHRpb25zKHNjaXBlbj05OTksIGRpZ2l0cz0xNSkKCmRhdGFfdXJsIDwtICJodHRwczovL2dpdGh1Yi5jb20vY3JvbmtpdGVkYXRhL3JzdHVkeWd1aWRlL2Jsb2IvbWFzdGVyL2RhdGEvYXpfcHBwX3ppcGNvZGVzLlJkYT9yYXc9dHJ1ZSIKbG9hZCAodXJsIChkYXRhX3VybCkgKQpgYGAKCgpUaGlzIG1hcmtkb3duIGdpdmVzIHlvdSBpbnN0cnVjdGlvbnMgZm9yIGltcG9ydGluZyBhbmQgdW5kZXJzdGFuZGluZyB0aGUgUFBQIGRhdGEgZm9yIHlvdXIgbWluaS1tZW1vLiBUaGVyZSBhcmUgb3RoZXIgYmFja2dyb3VuZCBkb2N1bWVudHMgYW5kIGV4YW1wbGUgc3RvcmllcyBpbiB0aGUgQ2FudmFzIG1vZHVsZSB0aGF0IHlvdSBjYW4gYWxzbyByZXZpZXcuIAoKIyMgRG93bmxvYWQgdGhlIGRhdGEgCgoKVG8gbG9hZCB0aGUgZGF0YSBpbnRvIHlvdXIgR2xvYmFsIEVudmlyb25tZW50IGFkZCB0aGlzIGxpbmUgdG8gYSBjb2RlIGNodW5rOiAKCiAgICAgICAgZGF0YV91cmwgPC0gImh0dHBzOi8vZ2l0aHViLmNvbS9jcm9ua2l0ZWRhdGEvcnN0dWR5Z3VpZGUvYmxvYi9tYXN0ZXIvZGF0YS9hel9wcHBfemlwY29kZXMuUmRhP3Jhdz10cnVlIgoKICAgICAgICBsb2FkICh1cmwgKCBkYXRhX3VybCkgKQogICAgICAgIAoKClRoaXMgd2lsbCBjcmVhdGUgdHdvIGRhdGEgZnJhbWVzIGluIHlvdXIgd29ya2luZyBlbnZpcm9ubWVudDogYGF6X3BwcF96aXBgLCB3aGljaCBpcyB0aGUgbGlzdCBvZiBsb2FucywgYW5kIGBhel9ieV96aXBjb2RlYCwgd2hpY2ggaGFzIGluZm9ybWF0aW9uIG9uIHRoZSB6aXAgY29kZXMuIAoKCiMjIFNvdXJjZXMKCgojIyMgUFBQIGxvYW5zCgpUaGUgb3JpZ2luYWwgZGF0YSB3YXMgcHVibGlzaGVkIGJ5IHRoZSBTQkEgaGVyZSA8aHR0cHM6Ly9zYmEuYXBwLmJveC5jb20vcy81bXlkMW54dXRvcTh3eGVjeDI1NjJiYXJ1ejc3NHNpNj4gb24gTWFyY2ggMSwgMjAyMS4gSSBkb3dubG9hZGVkIGFuZCB1bnppcHBlZCB0aGUgUFBQIHBvcnRpb24sIGFuZCByZWFkIGl0IGludG8gUiB1c2luZyBhIGRpZmZlcmVudCBwcm9ncmFtLiAKClRoZSBTQkEgaGFzIG5ldmVyIHJlbGVhc2VkIGEgcmVjb3JkIGxheW91dCBvciBkYXRhIGRpY3Rpb25hcnkgZm9yIHRoaXMgZGF0YSB0aGF0IEkgY2FuIGZpbmQuIEkgd29ya2VkIG9uIGEgcHJvamVjdCBvdmVyIHRoZSBDaHJpc3RtYXMgYnJlYWsgdXNpbmcgYW4gZWFybGllciB2ZXJzaW9uIG9mIHRoZSBkYXRhLCBzbyBJICp0aGluayogSSB1bmRlcnN0YW5kIG11Y2ggb2Ygd2hhdCBpdCBjb250YWlucy4gCgpJIHNlbGVjdGVkIGFib3V0IGhhbGYgb2YgdGhlIHZhcmlhYmxlcyB0aGF0IGFyZSBpbmNsdWRlZCBpbiB0aGUgb3JpZ2luYWwgZGF0YSwgYW5kIHNpbXBsaWZpZWQgYSBmZXcgYXMgc2hvd24gYmVsb3cuIEkgYWxzbyBjb252ZXJ0ZWQgYWxsIGNoYXJhY3RlciBmaWVsZHMgdG8gdXBwZXIgY2FzZSB0byBlYXNlIGZpbHRlcmluZywgYW5kIGNvbnZlcnRlZCB0aGUgWmlwIENvZGVzIHRvIDUtZGlnaXRzIC4gCgpUaGlzIGRhdGFzZXQgaW5jbHVkZXMgYWxsIGxvYW5zIHRoYXQgd2VyZSBtYWRlIHRvIGNvbXBhbmllcyBpbiBBcml6b25hLiBBIGhhbmRmdWwgKDYpIG9mIHRoZXNlIGFyZSBnb2luZyB0b3dhcmQgcHJvamVjdHMgaW4gb3RoZXIgc3RhdGVzLiAgIAoKSGVyZSBhcmUgdGhlIGNvbHVtbnMgSSBrZXB0LCBhbmQgd2hhdCBJIHVuZGVyc3RhbmQgdGhlbSB0byBtZWFuLiBBbnkgY2hhbmdlcyBvdGhlciB0aGFuIHRob3NlIGFib3ZlIGFyZSBpbmRpY2F0ZWQgaW4gdGhlIHJlY29yZCBsYXlvdXQuIAoKClRoZSBbbG9hbiBhcHBsaWNhdGlvbiBmb3JtXShodHRwczovL3d3dy5zYmEuZ292L3NpdGVzL2RlZmF1bHQvZmlsZXMvMjAyMC0wNC9QUFAtQm9ycm93ZXItQXBwbGljYXRpb24tRm9ybS1GaWxsYWJsZS5wZGYpIC4gVGhlcmUncyBvbmUgaW1wb3J0YW50IHRoaW5nIEkgZG9uJ3Qga25vdyB0aGUgYW5zd2VyIHRvOiBUaGVyZSBhcmUgbm8gcm93cyB3aXRoIGEgbG9hbiBzdGF0dXN0IHRoYXQgc3VnZ2VzdHMgdGhhdCBpdCB3YXMgZm9yZ2l2ZW4sIHRob3VnaCB3ZSBrbm93IGZyb20gcmVwb3J0cyB0aGF0IG1vcmUgdGhhbiAkMTAwIGJpbGxpb24gaGF2ZSBhbHJlYWR5IGJlZW4gZm9yZ2l2ZW4uIFRoZXJlIGlzIGEgImxvYW4gc3RhdHVzIiBmaWVsZCBpbiB0aGUgZGF0YSwgYnV0IHRoYXQgZG9lc24ndCBoYXZlIGFueXRoaW5nIHJlbGF0ZWQgdG8gZm9yZ2l2ZW5lc3MsIGFuZCB0aGUgIlBBSUQgSU4gRlVMTCIgaW5kaWNhdG9yIGRvZXNuJ3QgYWRkIHVwIHRvIG5lYXJseSBlbm91Z2ggbW9uZXkuIEknbSB0cnlpbmcgdG8gZmluZCBvdXQgd2hhdCB0aGUgYW5zd2VyIGlzIHRoZXJlLCBidXQgSSB3YW50ZWQgdG8gd2FybiB5b3Ugbm90IHRvIHVzZSB0aGF0IGNvbHVtbiB1bnRpbCB3ZSBnZXQgc29tZSBjbGFyaXR5IG9uIGl0LiAKCjxkaXYgc3R5bGU9IndpZHRoOjcwJSI+Cgpjb2x1bW4gbmFtZSAgICAgICB8IHR5cGUgfCBkZXNjcmlwdGlvbgotLS0tLS0tLS0tLS0tLS0tLS18IC0tLS0gfCAtLS0tLS0tLS0tLQppZCAgICAgICAgICAgICAgICB8ICBuICB8IEEgdW5pcXVlIGlkZW50aWZpZXIgc3VwcGxpZWQgYnkgdGhlIFNCQQpkYXRlX2FwcHJvdmVkICAgICB8ICBkICB8IERhdGUgdGhlIGxvYW4gd2FzIGluaXRpYWxseSBhcHByb3ZlZApzdGF0dXNfZGF0ZSAgICAgICB8ICBkICB8IFdoZW4gdGhlIHN0YXR1cyB3YXMgcmVwb3J0ZWQgKE5BIGlmIHVucmVwb3J0ZWQpCmJvcnJvd2VyICAgICAgICAgIHwgIGMgIHwgTmFtZSBvZiB0aGUgYm9ycm93ZXIsIGFsbCB1cHBlciBjYXNlCmFkZHJlc3MgICAgICAgICAgIHwgIGMgIHwgQWRkcmVzcyBvZiB0aGUgYm9ycm93ZXIKY2l0eSAgICAgICAgICAgICAgfCAgYyAgfApzdGF0ZSAgICAgICAgICAgICB8ICBjICB8CnppcCAgICAgICAgICAgICAgIHwgIGMgIHwgNS1kaWdpdCBaaXAgY29kZSBvZiB0aGUgYm9ycm93ZXIsIGFzIHJlcG9ydGVkIG9uIHRoZSBsb2FuCioqY2Vuc3VzX3ppcGNvZGUqKiAgICB8ICBjICB8IDUtZGlnaXQgInppcCBjb2RlIHRhYnVsYXRpb29uIGFyZWEiIHVzZWQgYnkgdGhlIENlbnN1cyBidXJlYXUqCmxvYW5fc3RhdHVzICAgICAgIHwgIGMgIHwgQmxhbmsgaWYgcmVkYWN0ZWQgYmVjYXVzZSBvZiBFWEVNUFRJT04gNCAtIFZFUlkgdW5jbGVhciB3aGF0IHRoaXMgbWVhbnMhIAp0ZXJtICAgICAgICAgICAgICB8ICBuICB8IE1vbnRocyB0byBwYXkgYmFjawppbml0aWFsX2FtdCAgICAgICB8ICBuICB8IEluaXRpYWwgYW1vdW50IGFwcHJvdmVkIGJ5IFNCQSwgYXMgcmVwb3J0ZWQgYnkgdGhlIGJhbmsuCnBheXJvbGxfYW10ICAgICAgIHwgIG4gIHwgQW1vdW50IHVzZWQgZm9yIHBheXJvbGwKbm9ucGF5cm9sbF9hbXQgICAgfCAgbiAgfCBUb3RhbCBhbW91bnQgdXNlZCBmb3Igb3RoZXIgY29zdHMgc3VjaCBhcyB1dGlsaXRpZXMsIHJlbnQsIG9yIGludGVyZXN0IG9uIGxvYW5zCmZyYW5jaGlzZSAgICAgICAgIHwgIGMgIHwgTmFtZSBvZiBhIGZyYW5jaGlzZWUgCmJ1c2luZXNzX3R5cGUgICAgIHwgIGMgIHwgSG93IHRoZSBidXNpbmVzcyBpcyBvcmdhbml6ZWQsIHN1Y2ggYXMgIlNPTEUgUFJPUFJJRVRPUiIgb3IgIkNPUlBPUkFUSU9OIgpsZW5kZXIgICAgICAgICAgICB8ICBjICB8IE5hbWUgb2Ygb3JpZ2luYXRpbmcgbGVuZGVyIChub3Qgc2VydmljaW5nIGxlbmRlcikKbGVuZGVyX3N0YXRlICAgICAgfCAgYyAgfApydXJhbF91cmJhbiAgICAgICB8ICBjICB8CmJ1c2luZXNzX2FnZSAgICAgIHwgIGMgIHwgSG93IGxvbmcgdGhlIGJ1c2luZXNzIGhhZCBiZWVuIG9wZW4gYmVmb3JlIHRoZSBsb2FuIC0gCnByb2plY3RfY2l0eSAgICAgIHwgIGMgIHwgQ2l0eSB3aGVyZSB0aGUgbW9uZXkgd2lsbCBiZSB1c2VkCnByb2plY3RfY291bnR5ICAgIHwgIGMgIHwgQ291bnR5IHdoZXJlIHRoZSBtb25leSB3aWxsIGJlIHVzZWQKcHJvamVjdF9zdGF0ZSAgICAgfCAgYyAgfCBTdGF0ZSB3aGVyZSB0aGUgY291bnR5IHdpbGwgYmUgdXNlZApqb2JzX3JlcG9ydGVkICAgICB8ICBuICB8IE51bWJlciBvZiBqb2JzICJzYXZlZCIgYnkgdGhlIGxvYW4KbmFpY3NfY29kZSAgICAgICAgfCAgYyAgfCBTdGFuZGFyZCBpbmR1c3RyeSBjb2RlIHVzZWQgaW4gdGhlIGZlZGVyYWwgZ292ZXJubWVudApuYWljc19zZWN0b3IgICAgICB8ICBjICB8IFNlY3RvciBvZiB0aGF0IHN0YW5kYXJkIGluZHVzdHJ5IGNvZGUsIHdoZXJlIGl0IHdhcyBhIHZhbGlkIG9uZQpuYWljc19kZXNjcmlwdCAgICB8ICBjICB8IDIwMTcgZGVzY3JpcHRpb24gb2YgdGhlIGluZHVzdHJ5LCBibGFuayBpZiBhIHByZXZpb3VzIHllYXIncyB2ZXJzaW9uIHVzZWQKcmFjZSAgICAgICAgICAgICAgfCAgYyAgfCBSYWNlIG9mIGJ1c2luZXNzIG93bmVyLCAiVU5BTlNXRVJFRCIgaXMgODUlIG9mIGxvYW5zLiBIaXNwYW5pYyBpcyBub3QgYSByYWNlLgpldGhuaWNpdHkgICAgICAgICB8ICBjICB8ICJISVNQQU5JQyBPUiBMQVRJTk8iLCAiTk9UIEhJU1BBTklDIE9SIExBVElOTyIsICJVTktOT1dOL05PVFNUQVRFRCIgKDg1JSBvZiBsb2FucykKZ2VuZGVyICAgICAgICAgICAgfCAgYyAgfCBTYW1lIHdpdGggZ2VuZGVyICAtIFVzdWFsbHkgbm90IGZpbGxlZCBvdXQKdmV0ZXJhbiAgICAgICAgICAgfCAgYyAgfCBTYW1lIHdpdGggdmV0ZXJhbiAtIFVzdWFsbHkgbm90IGZpbGxlZCBvdXQKbm9uX3Byb2ZpdCAgICAgICAgfCAgYyAgfCAiWSIgIGlmIHRoZSBib3Jyb3dlciBpcyBhIG5vbi1wcm9maXQgb3JnYW5pemF0aW9uCiAKPC9kaXY+CgoqIFRoZSBgY2Vuc3VzX3ppcGNvZGVgIGlzIHRoZSBvbmUgdGhhdCB5b3Ugd2lsbCB1c2UgdG8gbWF0Y2ggYWdhaW5zdCB0aGUgZGVtb2dyYXBoaWMgaW5mb3JtYXRpb24uIAoKVG8gZ2V0IGRlbW9ncmFwaGljIGluZm9ybWF0aW9uLCB3ZSBoYWQgdG8gdXNlICJ6aXAgY29kZSB0YWJ1bGF0aW9uIGFyZWFzIiwgd2hpY2ggaXMgd2hhdCB0aGUgQ2Vuc3VzIHVzZXMuIFRoZSByZWFzb24gaXMgdGhhdCBaaXAgQ29kZXMgYXJlIGFjdHVhbGx5IHBvc3RhbCBjb2RlcywgYW5kIHJlZmVsY3QgcG9zdCBvZmZpY2Ugcm91dGVzIHJhdGhlciB0aGFuIGFyZWFzLiBUaGV5IGNhbiBhbHNvIGNvbnRhaW4gcG9zdCBvZmZpY2UgYm94ZXMgYW5kIHNwZWNpYWwgemlwIGNvZGVzIGZvciBsYXJnZSBpbnN0aXR1dGlvbnMgbGlrZSBBU1UuIEkgY3JlYXRlZCBhIG5ldyBjb2x1bW4gaW4gdGhpcyBkYXRhc2V0IHRvIHJlZmxlY3QgdGhhdCBDZW5zdXMgemlwIGNvZGUsIHdoaWNoIGNhbiBiZSB1c2VkIHRvIG1hdGNoIGFnYWluc3QgdGhlIHJlc3Qgb2Ygb3VyIGRlbW9ncmFwaGljIGluZm9ybWF0aW9uLiAKCkNyZWF0aW5nIGl0IHdhcyBhIHR3by1zdGVwIHByb2Nlc3MuIEZpcnN0LCBJIG1hdGNoZWQgYWxsICJaQ1RBIiBkYXRhIGZyb20gdGhlIENlbnN1cyBpdHNlbGYgYWdhaW5zdCB0aGUgb3JpZ2luYWwgbGlzdCBhbmQga2VwdCB3aGF0ZXZlciBtYXRjaGVkLiBJZiB0aGV5IGRpZG4ndCwgSSBhcHBsaWVkIHRoZSBjZW5zdXMgWkNUQSBmb3VuZCBpbiB0aGUgIltVRFMgTWFwcGVyXShodHRwczovL3Vkc21hcHBlci5vcmcvemlwLWNvZGUtdG8temN0YS1jcm9zc3dhbGsvKSIgY3Jvc3N3YWxrLCB3aGljaCBpcyBhIGhlYWx0aCBjYXJlIGNvb3JkaW5hdGlvbiBjb25zb3J0aXVtIGNyZWF0ZWQgdG8gaGVscCBhZG1pbmlzdGVyIE9iYW1hY2FyZS4gIAoKT25lIGVsZW1lbnQgdGhhdCBpc24ndCBjbGVhciBpcyB3aGV0aGVyIHRoZSBsb2FuIHdhcyBmb3JnaXZlbiBvciBub3QgKHlldCkuIFRoZSBib3Jyb3dlciBoYXMgdXAgdG8gdHdvIHllYXJzIHRvIHJlcXVlc3QgZm9yZ2l2ZW5lc3MsIGFuZCB0aGV5IGNhbid0IGV2ZW4gYXNrIHVudGlsIHRoZXkndmUgdXNlZCBhbGwgdGhlIG1vbmV5LiAKCiMjIyBaaXAgY29kZSBkYXRhCgpUaGUgemlwIGNvZGUgZGF0YSB5b3UgYXJlIGdldHRpbmcgaXMgYSBjb21waWxhdGlvbiBvZiBzb3VyY2VzIHRoYXQgSSBjcmVhdGVkIGZvciBzb21lIHdvcmsgSSBkaWQgZm9yIFJldmVhbCBvdmVyIHRoZSBob2xpZGF5IGJyZWFrLiAoSXQgd2FzIHByZWxpbWluYXJ5IHdvcmsgdG8gZ2V0IHN0YXJ0ZWQgcmVwb3J0aW5nLCBhbmQgd29uJ3QgYmUgdXNlZCBpbiB0aGUgZmluYWwgc3RvcnkgLS0gdGhleSB3ZXJlIGluIHRoZSBwcm9jZXNzIG9mIGdlb2NvZGluZyBldmVyeSBsb2FuIHNvIHRoYXQgdGhleSBoYWQgQ2Vuc3VzIFRyYWN0IGluZm9ybWF0aW9uIHJhdGhlciB0aGFuIHppcCBjb2Rlcywgd2hpY2ggYXJlIG11Y2ggYmV0dGVyIGZvciBkZW1vZ3JhcGhpYyBwdXJwb3Nlcy4pCgoKIyMjIyBVU1BTIGJ1c2luZXNzZXMKClRoZXJlIGlzIG5vIGdvb2QgbWVhc3VyZSBvZiB0aGUgbnVtYmVyIG9mIGJ1c2luZXNzZXMgdGhhdCBleGlzdCBpbiBhbnkgc21hbGwgZ2VvZ3JhcGhpYyBhcmVhIGxpa2UgemlwIGNvZGUgb3IgQ2Vuc3VzIFRyYWN0LiBUaGUgcmVhc29uIGlzIHRoYXQgbW9zdCBnb3Zlcm5tZW50IHN1cnZleXMgb25seSBpbmNsdWRlIHByaXZhdGUsIGZvci1wcm9maXQgZW50aXRpZXMgd2l0aCBhdCBsZWFzdCA1IGVtcGxveWVlcy4gQWJvdXQgODAgcGVyY2VudCBvZiBhbGwgYnVzaW5lc3NlcyBoYXZlIE5PIGVtcGxveWVlcywgYW5kIGEgdmVyeSBsYXJnZSBwcm9wb3J0aW9uIG9mIHRoZSByZXN0IGhhdmUgZmV3ZXIgdGhhbiA1LiBUaGUgcHJvYmxlbSBpcywgdGhpcyBsb2FuIHByb2dyYW0gd2FzIHRhcmdldGVkIHNwZWNpZmljYWxseSBhdCB0aGVzZSBzbWFsbCBlbnRpdGllcyEgCgpUaGlzIG1lYW5zIGl0J3MgdmVyeSBkaWZmaWN1bHQgdG8gZXN0aW1hdGUgdGhlIHBlcmNlbnQgb2YgYWxsIGJ1c2luZXNzZXMgaW4gYSB6aXAgY29kZSB0aGF0IGdvdCBsb2FucyEgVGhlIGJlc3QgcHJveHkgSSBjb3VsZCBmaW5kIGlzIGZyb20gdGhlIFUuUy4gUG9zdGFsIFNlcnZpY2UsIHdoaWNoIHByb2R1Y2VzIFthIGZpbGUgZXZlcnkgcXVhcnRlciB0aGF0IGhhcyB0aGUgbnVtYmVyIG9mIGJ1c2luZXNzZXMgYW5kIHJlc2lkZW50aWFsIGFkZHJlc3Nlc10oaHR0cHM6Ly93d3cuaHVkdXNlci5nb3YvcG9ydGFsL2RhdGFzZXRzL3VzcHMuaHRtbCkgdGhhdCBjYW4gZ2V0IG1haWwuIEl0IGV4Y2x1ZGVzIFBPIGJveGVzLCBhbmQgd291bGQgY291bnQgYXMgInJlc2lkZW50aWFsIiBhIGJ1c2luZXNzIHJ1biBvdXQgb2YgYSBob21lLCBzbyBpdCdzIG5vdCBleGFjdC4gQnV0IGl0J3MgdGhlIGJlc3Qgd2UgY2FuIGZpbmQuIAoKIyMjIyBEZW1vZ3JhcGhpYyBpbmZvcm1hdGlvbgoKSSBvYnRhaW5lZCB0aGUgQ2Vuc3VzIGRhdGEgdXNpbmcgW1NvY2lhbCBFeHBsb3Jlcl0oaHR0cHM6Ly9zb2NpYWxleHBsb3Jlci5jb20pICwgd2hpY2ggeW91IGNhbiBhY2Nlc3MgdGhyb3VnaCB0aGUgQVNVIGxpYnJhcnkuIEl0IG1ha2VzIGl0IHJlbGF0aXZlbHkgZWFzeSB0byBvYnRhaW4gY3V0cyBvZiBDZW5zdXMgcHJvZHVjdHMgdGFpbG9yZWQgdG8geW91ciBuZWVkcy4gSSB1c2VkIHRoZSAyMDE0LTIwMTggQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSB0byBvYnRhaW4gYmFzaWMgZGVtb2dyYXBoaWMgaW5mb3JtYXRpb24gYnkgWmlwIENvZGUgVGFidWxhdGlvbiBhcmVhLiAKCiMjIyMgR2VvZ3JhcGhpYyBpbmZvcm1hdGlvbgoKWmlwIGNvZGVzIGRvbid0IGhhdmUgYmFzaWMgZ2VvZ3JhcGhpYyBlbGVtZW50cyBjb25uZWN0ZWQgdG8gdGhlbSEgIEkgdXNlZCB0aGUgQ2Vuc3VzIFRJR0VSIG1hcHBpbmcgZmlsZXMgdG8gYXR0YWNoIHRoZSBjb3VudHksIGxhdGl0dWRlLCBsb25naXR1ZGUsIGV0Yy4gdG8gdGhlIHpjdGFzIHVzaW5nIHRoZWlyIGNlbnRlciBwb2ludHMuIAoKCgojIyMgRGVtb2dyYXBoaWMgZGF0YSByZWNvcmQgbGF5b3V0CgoKY29sdW1uIG5hbWUgICAgIHwgdHlwZSB8IERlc2NyaXB0aW9uCi0tLS0tLS0tLS0tLS0tLSB8IC0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp6Y3RhICAgICAgICAgICAgfCBjIHwgIFRoZSBjZW5zdXMgemlwIGNvZGUgKG1hdGNoZXMgdG8gY2Vuc3VzX3ppcCBpbiB0aGUgcHBwIGRhdGEpCnppcGNvZGVfY2l0eSAgICB8IGMgfCAgVGhlIG5hbWUgb2YgdGhlIHBvc3Qgb2ZmaWNlLCBmcm9tIFVEUyBtYXBwZXIgICAgICAKc3RfY291bnR5X2ZpcCAgIHwgYyB8ICBBIHN0YW5kYXJkIGNvZGUgaW5kaWNhdGluZyB0aGUgY291bnR5IHRoYXQgdGhlIHppcCBjb2RlIGlzIGluCmNvdW50eV9uYW1lICAgICB8IGMgfCAgVGhlIG5hbWUgb2YgdGhhdCBjb3VudHkKbWV0cm9fbmFtZSAgICAgIHwgYyB8ICBNZXRybyBhcmVhIG5hbWUgaWYgdGhlcmUgaXMgb25lIGZvciB0aGF0IHppcCBjb2RlICAgICAgICAKdXNwc19idXNpbmVzc2VzIHwgbiB8ICMgb2YgYnVzaW5lc3MgYWRkcmVzc2VzIGVzdGltYXRlZCBieSAgdGhlIFVTIFBvc3RhbCBTZXJ2aWNlCnRvdF9wb3AgICAgICAgICB8IG4gfCBUb3RhbCBwb3B1bGF0aW9uICAoU29tZSBhcmUgemVybykKaG91c2Vob2xkcyAgICAgIHwgbiB8ICMgb2YgaG91c2Vob2xkcyAgICAgICAgIApwY3Rfd2hpdGVfbmggICAgfCBuIHwgUHJvcG9ydGlvbiBvZiBXaGl0ZSwgbm9uLUhpc3BhbmljIHBvcHVsYXRpb24gKHBlcmNlbnQgaW4gZGVjaW1hbHMpCnBjdF9ibGFja19uaCAgICB8IG4gfCBQcm9wb3JhdGlvbiBvZiBCbGFjaywgbm9uLUhpc3BhbmljICAgICAgCnBjdF9haWFuX25oICAgICB8IG4gfCBQcm9wb3J0aW9uIG9mIEFtZXJpY2FuIEluZGlhbiBvciBBbGFza2EgTmF0aXZlIG5vbi1IaXNwYW5pYyAgICAgICAgCnBjdF9hc2lhbl9uaCAgICB8IG4gfCBQcm9wb3J0aW9uIG9mIEFzaWFuIG5vbi1IaXNwYW5pYyAgICAgICAKcGN0X2hpc3BhbmljICAgIHwgbiB8IFByb3BvcnRpb24gb2YgSGlzcGFuaWMgb3IgTGF0aW5vIHBvcHVsYXRpb24gICAgICAgIAp6Y3RhX2V0aG5pYyAgICAgfCBuIHwgRXRobmljaXR5IGNhdGVnb3JpemF0aW9uIHVzaW5nIFVyYmFuIEluc3RpdHV0ZSdzIG1ldGhvZG9sb2d5ICAgICAgIAp3aGl0ZV9uaF9ncm91cCAgfCBuIHwgQ2F0ZWdvcml6YXRpb24gb2YgdGhlIHByb3Aub2YgV2hpdGUgbm9uLUhpc3BhbmljIHBvcHVsYXRpb24sIHVzaW5nIFVyYmFuIEluc3RpdHV0ZSAgICAgCm1lZGlhbl9pbmNfMjAxOCB8IG0gfCBNZWRpYW4gaW5jb21lIGluIDIwMTggZG9sbGFycyAgICAKaW5jb21lX2x0MjUgICAgIHwgbiB8IE51bWJlciBvZiBob3VzZWhvbGRzIHdpdGggbGVzcyB0aGFuICQyNSwwMDAgYW5udWFsIGluY29tZSAgICAgICAgCmluY29tZV8xNTBrdXAgICB8IG4gfCBOdW1iZXIgb2YgaG91c2Vob2xkcyB3aXRoICQxNTAsMDAwIGFubnVhbCBpbmNvbWUgb3IgbW9yZSAgICAgIAphZ2dyZWdhdGVfaW5jb21lIHwgbiB8IFRvdGFsIGhvdXNlaG9sZCBpbmNvbWUgKGNhbiBiZSBkaXZpZGVkIGJ5IGhvdXNlaG9sZHMgZm9yIGF2ZXJhZ2UgaW5jb21lKQpwY3RfY29sbGVnZV9ncmFkIHwgIG4gfCBQcm9wb3J0aW9uIG9mIGFkdWx0cyB3aXRoIGNvbGxlZ2UgZGVncmVlICAKcGN0X2tpZHNfZHJvcHBlZG91dCB8IG4gfCBQcm9wb3J0aW9uIG9mIHlvdXRoIDE4IGFuZCB1bmRlciB3aG8gZHJvcHBlZCBvdXQgb2Ygc2Nob29sCnVuZW1wbF9yYXRlICAgICAgICAgfCBuIHwgQXZlcmFnZSB1bmVtcGxveW1lbnQgcmF0ZSAyMDE0LTIwMTggICAgICAgIApsYXRpdHVkZSAgICAgICAgICAgIHwgbiB8IFRoZSBsYXRpdHVkZSBvZiB0aGUgY2VudGVyIHBvaW50IG9mIHRoZSB6aXAgY29kZSAgICAgICAgICAgCmxvbmdpdHVkZSAgICAgICAgICAgfCBuIHwgVGhlIGxvbmdpdHVkZSBvZiB0aGUgY2VudGVyIHBvaW50IG9mIHRoZSB6aXAgY29kZSAgICAgICAgIAogCgojIyBIb3cgdG8gdXNlIHRoZSBkZW1vZ3JhcGhpYyBkYXRhCgoKWW91IGNhbiB1c2UgdGhlIGRlbW9ncmFwaGljIGluZm9ybWF0aW9uIGluIHR3byB3YXlzOiAKCiogVG8gYXR0YWNoIGluZm9ybWF0aW9uIGFib3V0IHRoZSBhcmVhIHRvIGVhY2ggaW5kaXZpZHVhbCBsb2FuLCBhbGxvd2luZyB5b3UgdG8gbG9vayB1cCBidXNpbmVzc2VzIHRoYXQgd2VyZSBsb2NhdGVkIGluIHppcCBjb2RlcyB3aXRoIHNwZWNpZmljIGNoYXJhY3RlcmlzdGljcy4gCgoqIFRvIHVzZSB3aXRoIHN1bW1hcmlzZWQgaW5mb3JtYXRpb24gZnJvbSB0aGUgbG9hbnMgdG8gZmluZCBvdXQsIGZvciBleGFtcGxlLCB3aGljaCBsZW5kZXJzIHByb3ZpZGVkIGxvYW5zIGluIG1pbm9yaXR5IGFyZWFzLiAKCgpIZXJlIGFyZSB0d28gZXhhbXBsZXM6IAoKIyMjIE1hdGNoIHRoZW4gZmlsdGVyCgpIZXJlLCB3ZSdsbCBwdWxsIG91dCBpbmZvcm1hdGlvbiBvbiB0aGUgZXRobmljaXR5IG9mIHRoZSB6aXAgY29kZSwgYW5kIGF0dGFjaCBpdCB0byB0aGUgaW5kaXZpZHVhbCBsb2FuIGluZm9ybWF0aW9uLiBUaGVuIHdlIGNhbiBsb29rIHVwIGJ1c2luZXNzZXMgdGhhdCB3ZXJlIGluIGNlcnRhaW4gYXJlYXMuIAoKCkZpcnN0LCBjcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggdGhlIGluZm9ybWF0aW9uIHRoYXQgeW91IHdhbnQgdG8ga2VlcCBmcm9tIHRoZSBkZW1vZ3JhcGhpYyBmaWxlOiAKCmBgYHtyfQoKCmF6X2tlZXBfemlwIDwtCiAgYXpfYnlfemlwY29kZSAlPiUKICBzZWxlY3QgKCB6Y3RhLCB6aXBjb2RlX2NpdHksIGNvdW50eV9uYW1lLCB1c3BzX2J1c2luZXNzZXM6IGhvdXNlaG9sZHMsIHpjdGFfZXRobmljLCB3aGl0ZV9uaF9ncm91cCwgcGN0X2hpc3BhbmljLCBwY3Rfd2hpdGVfbmgsIHBjdF9haWFuX25oLCBwY3RfYmxhY2tfbmgsIAogICAgICAgICAgIG1lZGlhbl9pbmNfMjAxOCkKICAKCgpgYGAKCgpOb3cgam9pbiBpdCB0byB0aGUgbG9hbiBkYXRhIGFuZCBwaWNrIG91dCBsb2FucyB0aGF0IG1hdGNoIGEgZmV3IGNyaXRlcmlhIGFuZCBzZWxlY3Qgc29tZSBjb2x1bW5zIHlvdSBtaWdodCB3YW50IHRvIGV4YW1pbmU6CgpgYGB7ciByb3dzLnByaW50PSIyNSJ9Cgphel9wcHBfemlwICU+JQogIGxlZnRfam9pbiAoIGF6X2tlZXBfemlwLCBieT1jKCJjZW5zdXNfemlwIj0iemN0YSIpKSAlPiUKICBmaWx0ZXIgKCBjb3VudHlfbmFtZSA9PSAiWXVtYSBDb3VudHkiLCAKICAgICAgICAgICBzdHJfZGV0ZWN0ICh6Y3RhX2V0aG5pYywgIkhpc3BhbmljIiksCiAgICAgICAgICAgd2hpdGVfbmhfZ3JvdXAgPT0gIjAgdG8gMTAlIikgJT4lCiAgc2VsZWN0ICggYm9ycm93ZXIsIGNpdHksIGNlbnN1c196aXAsIGluaXRpYWxfYW10LCBldGhuaWNpdHksCiAgICAgICAgICBtZWRpYW5faW5jXzIwMTgsIHpjdGFfZXRobmljLCBwY3RfaGlzcGFuaWMsIGFkZHJlc3MKICAgICAgICAgICkgJT4lCiAgYXJyYW5nZSAoIGNlbnN1c196aXAsIGJvcnJvd2VyKQogICAgICAgICAgIAoKCmBgYAoKCiMjIyBHcm91cCB0aGVuIG1hdGNoCgpUaGUgb3Bwb3NpdGUgc3RyYXRlZ3kgY2FuIGJlIHVzZWQgdG8gc3VtbWFyaXplIGhvdyBsb2FucyB3ZXJlIG1hZGUgdG8gbWlub3JpdHkgYW5kIG5vbi1taW5vcml0eSB6aXAgY29kZXMuIFlvdSBjb3VsZCB1c2UgdGhpcyB0byBmaW5kIHBsYWNlcyB3aGVyZSB2ZXJ5IGZldyBidXNpbmVzc2VzIGdvdCBsb2FucyAsIG9yIHdoZXJlIG1vc3Qgb2YgdGhlIGJ1c2luZXNzZXMgZ290IGxvYW5zLCBpbiBtaW5vcml0eSBuZWlnaGJvcmhvb2RzLiAgVGhpcyBpcyBhIGxvdCBtb3JlIGNvbXBsaWNhdGVkIGFuZCB5b3UgaGF2ZSB0byBiZSBjYXJlZnVsIG9mIGRhdGEgYW5vbW9saWVzLCBidXQgaXQgaXMgYWxzbyB2ZXJ5IHBvd2VyZnVsOiBJdCBsZXRzIHlvdSBtYXAgb3V0IHRoZSBraW5kcyBvZiBuZWlnaGJvcmhvb2RzIHRoYXQgZ290LCBhbmQgZGlkbid0IGdldCwgbG9hbnMuICAKCllvdSBjYW4gbG9vayBhdCBob3cgbXVjaCB5b3UgY2FuIGRvIHdpdGggdGhpcyBhcHByb2FjaCBieSBsb29raW5nIGF0IFtvbmUgb2YgdGhlIG1ldHJvIGFyZWFzIEkgcHJvZmlsZWQgZm9yIHRoZSBSZXZlYWwgcHJvamVjdF0oaHR0cHM6Ly9jcm9ua2l0ZWRhdGEuZ2l0aHViLmlvL3JzdHVkeWd1aWRlL2V4dHJhL3R4X2RhbGxhcy5odG1sKS4gCgoKWW91IGNvdWxkIGFsc28gbG9vayBhdCB3aGV0aGVyIHRoZSBCaWRlbiBhZG1pbmlzdHJhdGlvbiBpcywgc28gZmFyLCBkb2luZyBtb3JlIHRvIHNlcnZlIG1pbm9yaXR5IG9yIHVuZGVyc2VydmVkIGFyZWFzLiAKCkhlcmUgaXMgYSBzaW1wbGUgZXhhbXBsZSwgd2hpY2ggbG9va3MgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBsb2FucyBieSBjb3VudHksIGRlcGVuZGluZyBvbiB0aGUgZXRobmljaXR5IG9mIHRoZSB6aXAgY29kZS4gCgojIyMjIFN0ZXAgMTogQWdncmVnYXRlIChzdW0pIHRoZSBQUFAgbG9hbnMKCkZpcnN0LCB3ZSBoYXZlIHRvIGdldCB0aGUgbnVtYmVyIG9mIGxvYW5zIGFuZCBzb21lIG90aGVyIGRhdGEgYWJvdXQgZWFjaCB6aXAgY29kZSBmcm9tIHRoZSBQUFAgbG9hbiBkYXRhLiBXZSBzaG91bGQgYWxzbyBiZSBzdXJlIHdlIGtub3cgaG93IG1hbnkgYnVzaW5lc3NlcyBnb3QgbG9hbnMsIG5vdCBqdXN0IHRoZSBudW1iZXIgb2YgbG9hbnMsIGJlY2F1c2Ugd2UncmUgZ29pbmcgdG8gd2FudCB0byBnZXQgYSByYXRlIG9mIHBhcnRpY2lwYXRpb24gbGF0ZXIgb24uIAoKCmBgYHtyfQoKcHBwX3ppcHRvdGFscyA8LSAKICBhel9wcHBfemlwICU+JQogIGdyb3VwX2J5ICggY2Vuc3VzX3ppcCApICU+JQogIHN1bW1hcmlzZSAoIGxvYW5zID0gbigpLAogICAgICAgICAgICAgIGJvcnJvd2VycyA9IG5fZGlzdGluY3QgKCBib3Jyb3dlciwgemlwKSAsIAogICAgICAgICAgICAgIHRvdGFsX2Ftb3VudCA9IHN1bSAoIHBheXJvbGxfYW10ICsgbm9ucGF5cm9sbF9hbXQpCiAgKQoKYGBgCgpOb3cgd2UncmUgZ29pbmcgdG8gbWF0Y2ggdGhlbSBhZ2FpbnN0IHRoZSB6aXAgY29kZSBpbmZvcm1hdGlvbiB3ZSBrZXB0IGVhcmxpZXIsIG1ha2luZyBzdXJlIHRvIGtlZXAgYWxsIG9mIHRoZSByb3dzIChub3QganVzdCB0aG9zdCB0aGF0IGhhZCBsb2FucyBpbiB0aGVtKS4gVGhpcyB3aWxsIGRyb3Agb3V0IGFueSB6aXBjb2RlcyB0aGF0IGFyZW4ndCByZWFsbHkgaW4gQXJpem9uYSBvciBhcmUgYmxhbmsgaW4gb3VyIFBQUCBkYXRhLiBXZSBhbHNvIGhhdmUgdG8gbWFrZSB0aGUgbnVtYmVyIG9mIGxvYW5zIHplcm8gaW4gemlwIGNvZGVzIHRoYXQgZGlkbid0IGV4aXN0IGluIG91ciBQUFAgbG9hbiBkYXRhLiAgCgooVGhpcyBpcyBhICJsZWZ0X2pvaW4iLCB3aGljaCBtZWFucyAia2VlcCBldmVyeXRoaW5nIGZyb20gdGhlIGZpcnN0IGRhdGEgZnJhbWUgbWVudGlvbmVkLCBhbmQgb25seSB0aGUgdGhpbmdzIHRoYXQgbWF0Y2ggZnJvbSB0aGUgc2Vjb25kIG9uZSBsaXN0ZWQuIikKCgpgYGB7cn0KCnBwcF96aXBfc3VtcyA8LSAKICBhel9rZWVwX3ppcCAlPiUKICBsZWZ0X2pvaW4gKCBwcHBfemlwdG90YWxzLCBieT1jKCJ6Y3RhIj0iY2Vuc3VzX3ppcCIpKSAlPiUKICAjIHdlIGFyZSBsZWZ0IHdpdGggc29tZSBOQSdzIGJlY2F1c2Ugbm90IGV2ZXJ5IHppcCBjb2RlIGhhZCBhbnkgbG9hbnMKICAjIFRoZXJlJ3MgYSBzaG9ydGN1dCB3YXkgdG8gZG8gdGhpcywgYnV0IEkgZG9uJ3Qgd2FudCB0byBtYWtlIGl0IG1vcmUgY29uZnVzaW5nIHRoYW4gbmVjZXNzYXJ5IHJpZ2h0IG5vdy4KICBtdXRhdGUgKCBsb2FucyA9IHJlcGxhY2VfbmEgKGxvYW5zLCAwKSwgCiAgICAgICAgICAgYm9ycm93ZXJzID0gcmVwbGFjZV9uYSAoYm9ycm93ZXJzLCAwKSwgCiAgICAgICAgICAgdG90YWxfYW1vdW50ID0gcmVwbGFjZV9uYSAodG90YWxfYW1vdW50LCAwKSkgCiAgCgpgYGAKCgpJbiBwcmFjdGljZSwgd2UnZCBoYXZlIHRvIGRlY2lkZSB3aGF0IHRvIGRvIGluIGNhc2VzIGluIHdoaWNoIHRoZXJlIHdlcmUgbW9yZSBsb2FucyB0aGFuIGJ1c2luZXNzZXMhIEluIHNvbWUgY2FzZXMsIHRoZSBQb3N0YWwgU2VydmljZSBoYWQgbm8gYnVzaW5lc3MgYWRkcmVzc2VzIGJ1dCB0aGVyZSB3ZXJlIGxvYW5zIC4gSW4gb3RoZXJzLCB0aGVyZSB3ZXJlIG1hbnkgbW9yZSBsb2FucyB0aGFuIHRoZXJlIHdlcmUgYnVzaW5lc3Nlcy4gWW91IGhhdmUgc29tZSBjaG9pY2VzOiAKCiogU2V0IHRoZSAlIG9mIGJ1c2luZXNzZXMgd2l0aCBsb2FucyB0byAxMDAlIGlmIHRoZSBudW1iZXIgb2YgbG9hbnMgd2FzIG1vcmUgdGhhbiB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBidXNpbmVzc2VzLiAKCiogQWRkIHRvZ2V0aGVyIHRoZSBudW1iZXIgb2YgYnVzaW5lc3NlcyBhbmQgdGhlIG51bWJlciBvZiBob3VzZWhvbGRzLCB0byBnZXQgYSBzdGFibGUgYmFzaXMgZm9yIGEgY29tcGFyaXNvbi4gVGhpcyBiYXNpY2FsbHkgc2F5cywgIm91dCBvZiBhbGwgb2YgdGhlIGVudGl0aWVzIHdlIGtub3cgb2YgaW4gdGhpcyB6aXAgY29kZSwgd2hhdCBwb3J0aW9uIGdvdCBsb2Fucz8iIElmIGl0J3MgYSBidXNpbmVzcyBkaXN0cmljdCwgdGhhdCB3b3VsZCBiZSBoaWdoLiBCdXQgaXQgd291bGQgbmV2ZXIgYmUgbW9yZSB0aGFuIDEwMCUhIAoKKiBNb3ZlIHVwIGEgbGV2ZWwgb2YgYWdncmVnYXRpb24gLS0gbG9vayBhdCB0b3RhbHMgYnkgY291bnR5IGFuZCBldGhuaWNpdHksIG9yIGdyb3VwIHRoZSB6aXBjb2RlcyB0b2dldGhlciBzb21lIG90aGVyIHdheSwgdG8gc3VtbWFyaXplIHRoZSBkYXRhIGFuZCBwYXBlciBvdmVyIHRoZSBkYXRhIHByb2JsZW1zLiAKCiogRG9uJ3Qgd29ycnkgYWJvdXQgaXQsIGFuZCBwaWNrIG91dCBzb21lIGludGVyZXN0aW5nIHppcCBjb2Rlcywgc3VjaCBhcyBzb21lIHdpdGggcmVsYXRpdmVseSBsb3cgaW5jb21lIG9yIHNvbWUgcHJlZG9taW5hbnQgZXRobmljaXR5LCBhbmQgdGhlbiBjb21wYXJlIHRoZWlyIHRvdGFsIGxvYW4gcmF0ZXMgd2l0aCBldmVyeW9uZSBlbHNlLiAKCiogVXNlIHRoZSBhbm9tYWxpZXMgdG8geW91ciBhZHZhbnRhZ2UgLS0gbG9vayBhdCB0aG9zZSBwbGFjZXMgb24gYSBtYXAgb3IgYSBzYXRlbGxpdGUgaW1hZ2UsIGFuZCBzZWUgaWYgdGhleSBtaWdodCBiZSBnb29kIHBsYWNlcyB0byBjZW50ZXIgYSBzdG9yeSEgCgoKSGVyZSdzIGFuIGV4YW1wbGUgb2YgYWdncmVnYXRpbmcgdG8gdGhlIGNvdW50eSBsZXZlbDogCgpgYGB7cn0KCgphel9wcHBfY291bnR5IDwtIAogICBwcHBfemlwX3N1bXMgJT4lCiAgIGdyb3VwX2J5IChjb3VudHlfbmFtZSwgemN0YV9ldGhuaWMgKSAlPiUKICAgc3VtbWFyaXNlIChhY3Jvc3MgICggYyggdXNwc19idXNpbmVzc2VzLCB0b3RfcG9wLCBob3VzZWhvbGRzLCBsb2FucywgYm9ycm93ZXJzLCB0b3RhbF9hbW91bnQpICwgc3VtLCBuYS5ybT1UKSkKICAKCmBgYAoKCk5vdywgZm9yIGVhY2ggZ3JvdXAsIGNhbGN1bGF0ZSB0aGUgcGVyY2VudCBvZiB0aGUgYnVzaW5lc3NlcyB0aGF0IHdlcmUgYm9ycm93ZXJzLiBDYXAgaXQgYXQgMTAwJS4gSSdsbCBkbyBpdCBpbiB0d28gc3RlcHMgc28gaXQncyBhIGxpdHRsZSBtb3JlIG9idmlvdXM6CgpgYGB7cn0KCgphel9wcHBfY291bnR5ICU+JQogIG11dGF0ZSAoIHBjdF9ib3Jyb3dlZCA9IGJvcnJvd2VycyAvIHVzcHNfYnVzaW5lc3NlcyAqIDEwMCApICU+JQogICMgZml4IGl0LgogIG11dGF0ZSAoIHBjdF9ib3Jyb3dlZCA9IAogICAgICAgICAgICAgaWZfZWxzZSAoIHBjdF9ib3Jyb3dlZCA8PSAxMDAsIHBjdF9ib3Jyb3dlZCwgMTAwICkpICU+JQogICMgcm91bmQgaXQgb2ZmLiAKICBtdXRhdGUgKHBjdF9ib3Jyb3dlZCA9IHJvdW5kIChwY3RfYm9ycm93ZWQsIDIpKQpgYGAKWW91IGNhbiBzZWUgd2UgZ2V0IHJlYWxseSB3ZWlyZCBhbnN3ZXJzIGZvciB0aGUgc21hbGwgY291bnRpZXMgd2l0aCBmZXcgYnVzaW5lc3NlcyByZWdpc3RlcmVkIHdpdGggdGhlIFBvc3RhbCBTZXJ2aWNlLiBJbiB0aGlzIGNhc2UsIHdlIG1pZ2h0IHdhbnQgdG8gYWRkIHRvZ2V0aGVyIHRoZSBudW1iZXIgb2YgaG91c2Vob2xkcyBhbmQgYnVzaW5lc3NlcywgYW5kIHRoZW4gdHJ5IGl0LiBJdCdzIG5vdCBhd2Vzb21lLCBidXQgaXQgYXQgbGVhc3QgZ2l2ZXMgdXMgYSByZWFzb25hYmxlIHJhdGUgb2Ygc29tZSBraW5kOgoKYGBge3J9CgoKYXpfcHBwX2NvdW50eSAlPiUKICBtdXRhdGUgKCBwY3RfYm9ycm93ZWQgPSBib3Jyb3dlcnMgLyAodXNwc19idXNpbmVzc2VzICsgaG91c2Vob2xkcykgKiAxMDAgKSAlPiUKICAjIGZpeCBpdC4KICBtdXRhdGUgKCBwY3RfYm9ycm93ZWQgPSAKICAgICAgICAgICAgIGlmX2Vsc2UgKCBwY3RfYm9ycm93ZWQgPD0gMTAwLCBwY3RfYm9ycm93ZWQsIDEwMCApKSAlPiUKICAjIHJvdW5kIGl0IG9mZi4gCiAgbXV0YXRlIChwY3RfYm9ycm93ZWQgPSByb3VuZCAocGN0X2JvcnJvd2VkLCAyKSkKCgpgYGAKCkxldCdzIGRvIHRoZSBzYW1lIHRoaW5nLCBidXQgY29tcHV0ZSBzb21lIGF2ZXJhZ2VzIGJ5IGNvdW50eSBzbyB3ZSBrbm93IGlmIGl0J3MgZGlmZmVyZW50IGZyb20gdGhlIHRvdGFsLiAKCgoKCmBgYHtyfQoKYXpfcHBwX2NvdW50eSAlPiUKICBtdXRhdGUgKCBwY3RfYm9ycm93ZWQgPSBib3Jyb3dlcnMgLyAodXNwc19idXNpbmVzc2VzICsgaG91c2Vob2xkcykgKiAxMDAgKSAlPiUKICAjIGZpeCBpdC4KICBtdXRhdGUgKCBwY3RfYm9ycm93ZWQgPSAKICAgICAgICAgICAgIGlmX2Vsc2UgKCBwY3RfYm9ycm93ZWQgPD0gMTAwLCBwY3RfYm9ycm93ZWQsIDEwMCApKSAlPiUKICAjIHJvdW5kIGl0IG9mZi4gCiAgbXV0YXRlIChwY3RfYm9ycm93ZWQgPSByb3VuZCAocGN0X2JvcnJvd2VkLCAyKSwgCiAgICAgICAgICBjb3VudHlfcGN0X2JvcnJvd2VkID0gIHJvdW5kIChzdW0oIGJvcnJvd2VycykgLyBzdW0oIHVzcHNfYnVzaW5lc3NlcyArIGhvdXNlaG9sZHMpICAqIDEwMCwgMikpIAoKYGBgCgpGaW5hbGx5LCBsZXQncyBqdXN0IHBpY2sgb3V0IHNvbWUgb2YgdGhlIG51bWJlcnMgYW5kIGZsaXAgdGhlbSBhcm91bmQgc28gdGhhdCB5b3UgY2FuIGNvbXBhcmUgInNwcmVhZHNoZWV0IiBzdHlsZTogCgpgYGB7ciByb3dzLnByaW50PSIxNSJ9Cgphel9wcHBfY291bnR5ICU+JQogICNjb3BpZWQgZnJvbSBhYm92ZQogIG11dGF0ZSAoIHBjdF9ib3Jyb3dlZCA9IGJvcnJvd2VycyAvICh1c3BzX2J1c2luZXNzZXMgKyBob3VzZWhvbGRzKSAqIDEwMCApICU+JQogIG11dGF0ZSAoIHBjdF9ib3Jyb3dlZCA9IAogICAgICAgICAgICAgaWZfZWxzZSAoIHBjdF9ib3Jyb3dlZCA8PSAxMDAsIHBjdF9ib3Jyb3dlZCwgMTAwICkpICU+JQogIG11dGF0ZSAocGN0X2JvcnJvd2VkID0gcm91bmQgKHBjdF9ib3Jyb3dlZCwgMiksIAogICAgICAgICAgY291bnR5X3BjdF9ib3Jyb3dlZCA9ICByb3VuZCAoc3VtKCBib3Jyb3dlcnMpIC8gc3VtKCB1c3BzX2J1c2luZXNzZXMgKyBob3VzZWhvbGRzKSAgKiAxMDAsIDIpKSAgJT4lCiAgI3RoaXMgcGFydCBpcyBuZXc6CiAgc2VsZWN0ICggemN0YV9ldGhuaWMsIGNvdW50eV9uYW1lLCBjb3VudHlfcGN0X2JvcnJvd2VkLCBwY3RfYm9ycm93ZWQgKSAlPiUKICBmaWx0ZXIgKHN0cl9kZXRlY3QgKHpjdGFfZXRobmljLCAiMDF8MDR8MDYiKSApICU+JQogIHBpdm90X3dpZGVyICggbmFtZXNfZnJvbSA9IHpjdGFfZXRobmljLCB2YWx1ZXNfZnJvbT1wY3RfYm9ycm93ZWQpCgoKCmBgYAoKQmVjYXVzZSB3ZSd2ZSBjb21wYXJlZCB0aGUgbnVtYmVyIG9mIGJvcnJvd2VycyB0byBhIGNvbWJpbmF0aW9uIG9mIGJ1c2luZXNzZXMgYW5kIGhvdXNlaG9sZHMsIGl0J3MgYSBsaXR0bGUgaGFyZCB0byBkZXNjcmliZSB0aGlzIGFuc3dlci4gQnV0IGhlcmUncyBhIHN0YWIgYXQgaXQ6IAoKICAgICAgSW4gTWFyaWNvcGEgQ291bnR5LCB0aGUgcHJlZG9taW5hbnRseSBXaGl0ZSBhcmVhcyBoYWQgYWJvdXQgNjggcGVyY2VudCBoaWdoZXIgcmF0ZXMgb2YgYm9ycm93aW5nIHRoYW4gcHJlZG9taW5hbnRseSBMYXRpbm8gYXJlYXMsIGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgYnVzaW5lc3NlcyBhbmQgaG91c2Vob2xkcyBpbiBlYWNoIHppcCBjb2RlLgoK