< Find Me a Venture Capitalist



Introduction

This tutorial demonstrates how I am utilizing fundManageR, reproducible research, data visualization and data science to advise two of my portfolio companies who are preparing for an institutional fund-raising round. This exercise will focus on exploring and analyzing venture capitalists.

But Before We Get Started

Accurate, clean, and tidy data is an incredible resource, but it is only a tool.

Success is about a confluence of factors including, but not limited to, luck, execution, perserverence, communication, and a clear, but flexible, understanding of the end goal. Data, analytical skills, programming abilities, and machine learning proficiency are high powered weapons but in isolation they won’t get you very far; they are only tools.

Now, let’s get started

The Mission: Identify and Target Venture Capital Firms Headquartered in a Specified Area

Today’s mission is to find venture capitalists head-quartered in Maryland, Washington D.C., Virginia, New York, Massachusetts, and Florida. We are limiting it to these locations to focus on areas that me, and the portfolio companies have strong ties in.

The workflow is straight forward:

  • Access the most recent monthly ADV Manager summary data
  • Exclude managers outside of our specified locations
  • Exclude all non venture exempt managers
  • Access detailed manager data by piping the CRDs through the get_data_adv_managers_filings function
  • Explore the data
  • Draw some conclusions.

Important Caveat

This is a crude hack for isolating venture capitalists. A pure play venture firm, in many circumstances, utilizes a special exemption allowing for venture managers to avoid many of the standard reporting requirements mandated on SEC regulated investment managers. The SEC captures information and discloses it in its standard monthly reporting data via a logical field that discloses whether a manager has utilized the venture exemption.

It is extremely important to note that this method limits us to only venture managers utilizing this exemption. This method won’t help us find managers who have venture as one of their product lines, like say Texas Pacific Group, or a venture manager that is registered but hasn’t qualified or applied for this exemption like 137 Ventures.

Context and common sense is as important as a powerful data driven work-flow. This tutorial is meant to empower but not mislead you into thinking the results produced are all-encompassing, because they are not. What tutorial will do is provide you with a crude method to acquire data that we know meet the venture criteria we defined.

Step 1 - Import Most Recent Monthly Summary ADV Data

packages <-
  c('fundManageR', 'dplyr', 'magrittr', 'tidyr', 'formattable', 'tibble') # packages we need
lapply(packages, library, character.only = T)

all_managers_recent <- 
  get_data_adv_managers_periods_summaries(all_periods = F, only_most_recent = T, is_exempt = c(F, T), file_directory = NULL, folder_name = NULL)

We now have the data for the 15,461 SEC regulated managers registered as of October 3rd, 2016 which we can pare down according to our search criteria.

Step 2 - Find Exempt Venture Managers in Our Target Locations

Using hasExemptionAsSolelyVentureAdviser and stateOfficePrimary fields we can quickly filter down our data.

locations <- 
  c("DC", "MA", "VA", "FL", "NY", "MD", "NY")
vcs_in_location_df <- 
  all_managers_recent %>%
  dplyr::filter(stateOfficePrimary %in% locations, # comma acts as AND in dplyr
  hasExemptionAsSolelyVentureAdviser == T)

The filtered data includes the 218 registered managers that meet our search criteria. Soon we will take this and use the get_data_adv_managers_filings function to acquire all the disclosed information about each of these managers.

Before doing that I want to highlight something you notice while exploring the vcs_in_location_df data. Some of the most pertinent fields containing information about a manager’s assets under management, employee counts, client counts, fee structures are NA.

The venture exemption allows these managers to avoid the periodic reporting of this information, something non-exempt managers are forced to do. The good news is this data does exist and fundManageR will get it for you, the downside is the data is reported annually and is buried deep in the messy html of the manager’s accepted ADV form.

Step 3 - Acquire Detailed Manager Data

The get_data_adv_managers_filings function requires either free text search names or numeric CRDs to acquire the ADV filing data. Search names may produce less accurate results, and often return managers whose information we did not want.

CRDs are a unique identifier, the primary key of the SEC’s IAPD database for an entity, and if we have a firm’s CR it will always produce accurate results. Our prior work produced each manager’s CRD which we will use to power our next function call.

Please Be Patient

This search will take a while given we are parsing 218 managers so be patient. This function will process a few gigabytes of data to produce our final results. You can track the progress with the message output but I’d recommend doing something else for about an hour or so while this runs.

search_crds <- 
  vcs_in_location_df$idCRD # create vector of CRDs
all_manager_data <-
  get_data_adv_managers_filings(
    crd_ids = search_crds,
    all_sections = T,
    search_names = NULL,
    assign_to_enviornment = T
  )

Step 4 - Explore the Data

Now that we’ve acquired the data lets explore it and answer a few questions.

  • What are each manager’s reported total assets under management?
  • What is the distribution of assets under management by state?
  • How many fund’s does each manager control?
  • What conclusions can we draw from the numeric data about the managers?

Calculate Assets Under Management by Manager

The first thing we want to do is calculate the summary information we’d normally find in the monthly ADV data for these venture exempt managers.

We can do this using the data in the section7BPrivateFundReporting table. We will produce the desired information by grouping the information by CRD and manager name, and summarizing the total assets under management, count of investors and count of fund vehicles.

Finally we will join that data with descriptive information about the manager’s state headquarters and website.

fund_manager_totals <- 
  section7BPrivateFundReporting %>% 
  group_by(nameEntityManager, idCRD) %>%  # set group
  summarise(amountAUMTotal = sum(amountFundGrossAUM, na.rm = T),
         countVehicles = n(),
         countInvestors = sum(countFundOwners, na.rm = T)) %>% 
  left_join(
    vcs_in_location_df %>%  # join the office state
      select(idCRD, stateOfficePrimary)
  ) %>% 
  left_join(
    managerWebsite %>% # join the manager website
      dplyr::select(idCRD, urlManager)
  ) %>% 
  select(nameEntityManager, idCRD, urlManager, stateOfficePrimary, everything()) %>% 
  ungroup() %>% # ungroup
  arrange(desc(amountAUMTotal))
fund_manager_totals

Venture Manager Breakdown by Location

Next we will use the data to paint a picture of venture landscape by location. To make this information visual and explorable I will show you how to use an experimental feature of the formattable package which embeds htmlwidgets into a table.

In order for this code to work you need to have the packages listed below loaded, you can follow the instructions in the code comments to install them if you have yet to do so. The experimental formattable functions have yet to be integrated into the package so the functions must be sourced from my github gist.

library(sparkline) #devtools::install_github("htmlwidgets/sparkline")
library(scatterD3) # devtools::install_github("juba/scatterD3")
library(htmlwidgets) # devtools::install_github("ramnathv/htmlwidgets")
source("https://gist.githubusercontent.com/abresler/8080a046794f97b8e3174b871b8429c0/raw/06f9c66552775facda7aeb7e6780ed74e9fda1c3/htmlwidget_tests.r")

Now we can create the table.

The first step is to use dplyr to create the summary data. We do this by grouping by state, removing the CRD ID, and using the summarise_if function to quickly calculate the sum of all the remaining numeric columns.

Next, we will shorten the column names to make them easier to print. We are left with the core summary data by state but still need to augment it by joining additional information and our visualizations. We don’t have the fund manager count by state so we can derive that and join it in with our existing data. Finally we will join our visualization columns, scatter plots of assets under management by fund vehicles and assets under management by investor count.

ft_lm <-
  fund_manager_totals %>%
  dplyr::select(-idCRD) %>%
  group_by(state = stateOfficePrimary) %>%
  summarise_if(.predicate = is.numeric,
               funs(. %>% sum)) %>% 
  rename(vehicles = countVehicles, investors = countInvestors, AUM = amountAUMTotal) %>%
  left_join(
    fund_manager_totals %>%
      dplyr::select(-idCRD) %>%
      group_by(state = stateOfficePrimary) %>%
      summarise(managers = n())
  ) %>%
  left_join(
    fund_manager_totals %>%
      dplyr::select(-idCRD) %>%
      group_by(state = stateOfficePrimary) %>%
      summarize(
        aumByFundCount = scatter_cell(
          countVehicles,
          amountAUMTotal / 1000000, ## divide by 1M
          xlab = "Fund Vehicles",
          ylab = "AUM Millions",
          tooltip_text = paste0(
            nameEntityManager, # Add the tool tip
            "<br><strong>Amount AUM: </strong>",
            amountAUMTotal,
            "<br><strong>Fund Vehicles: </strong>",
            countVehicles
          ),
          point_size = 20, # modify point size
          hover_size = 6, # change hover size
          ellipses = T, # add grouping ellipse
          hover_opacity = 1, # change hover opacity
          height = 200, # modify the height
          width = 220 # modify the width
        ),
        aumByInvestorCount = scatter_cell(
          countInvestors,
          amountAUMTotal / 1000000,
          tooltip_text = paste0(
            nameEntityManager,
            "<br><strong>Amount AUM:</strong>",
            amountAUMTotal,
            "<br><strong>Investor Total: </strong>",
            countInvestors
          ),
          xlab = "Fund Investors",
          ylab = "AUM Millions",
          point_opacity = 0.5,
          hover_size = 4,
          hover_opacity = 1,
          point_size = 20,
          ellipses = T,
          colors = "#A94175",
          height = 200,
          width = 270
        )
      )
  ) %>%
  formattable() %>%
  as.htmlwidget() %>% 
  suppressMessages()
ft_lm$dependencies <- c(ft_lm$dependencies, # setup the htmlwidget
                        htmlwidgets:::widget_dependencies("scatterD3", "scatterD3"))

Fund Manager Exploration

Next we will try to better understand our list of managers. We also want to make it easy to navigate to the manager’s webpage which we can do by taking our data from step 1 and layering in some html. Finally, we want to add a visual sparkline showcasing a manager’s assets under management by fund, which will give us a good visual cue on the AUM variance between funds, number of funds and overall fund sizes.

manager_df <-
  fund_manager_totals %>%
  ungroup %>%
  dplyr::select(-idCRD) %>%
  mutate(urlManager = ifelse(
    urlManager %>% is.na(),
    NA,
    list(
      "<a href ='",
      urlManager, # create a clickable url that opens a new window
      "' target ='_blank'>",
      urlManager,
      "</a>"
    ) %>% invoke(paste0, .)
  )) %>%
  dplyr::rename(
    url = urlManager, # change naming to make the table fit
    state = stateOfficePrimary,
    investors = countInvestors,
    vehicles = countVehicles,
    AUM = amountAUMTotal
  )

manager_ft <-
  formattableWithSL(
    TableDF = manager_df,
    rawDF =
      section7BPrivateFundReporting %>% 
      select(nameEntityManager, fundAUM = amountFundGrossAUM) %>% 
      data.frame(), # requires data.frame unforutantely 
    key = "nameEntityManager", # key for spark line
    SLfield = "fundAUM" # variable visualized in spark line
  ) %>% 
  suppressMessages()
manager_ft

A Data Driven View of the Manager Landscape

In this final step we will utilize some important numeric descriptors to draw some conclusions about the landscape of our managers. To achieve this we will use a statistical analysis tool known as Principal Components Analysis[PCA].

PCA is a powerful way to take numeric data and break it down into a set of components that explain the variance of the data. The algorithm returns a set scores for each the variables. These scores include a list of components the length of the number of variables that fully explain the variance. We will isolate, explore and visualize the first two principal components.

We have assembled some use numeric data but there are a couple of we can join in to enhance this analysis. In addition to the assets under management, vehicle count, and investor count we want to include information that proxies a firm’s operational size, something we can get by including a count of their offices. We also want to include information a manager’s average fund profile, something we can do by joining in information about a manager’s weighted average investment minimum and percentage breakdown of various fund characteristics {percent of international investors, percent from fund of funds, percent from feeder fund, etc..}. Finally we want information that profiles a manager’s depth of relationships with services providers. We can achieve this by joining in a count of the service providers by service also disclosed in section7BPrivateFundReporting.

Once completed, we will take the data, isolate the the numeric fields, scale to mean zero and use prcomp function to apply the principal components algorithm. We will then explore the loading scores, visualize the result first two components and draw some conclusions from the data.

Assemble Data for PCA

fund_totals <- 
  section7BPrivateFundReporting %>%
  group_by(idCRD, nameEntityManager) %>%
  summarise(
    countFunds = max(numberFund),
    amountTotalAUM = sum(amountFundGrossAUM, na.rm = T),
    countTotalFundOwners = sum(countFundOwners, na.rm = T)
  ) %>%
  ungroup
service_provider_df <- 
  section7BPrivateFundReporting %>% 
  select(idCRD, matches("^name[A-Z]")) %>% 
  select(-c(nameFund, nameFundGPManagerTrusteeDirector, nameFundFeederGPManagerTrusteeDirector)) %>% 
  select(-matches("nameFundFeederGPManagerTrusteeDirector|nameCustodianBusiness|EntityManager")) %>% 
  gather(item, value, -c(idCRD), na.rm = T) %>% 
  mutate(item = item %>% str_replace_all("[0-9]", '')) %>% 
  distinct() %>% 
  group_by(idCRD, item) %>% 
  summarise(count = n()) %>% 
  mutate(item = item %>% str_replace_all('name', 'countFund')) %>%
  spread(item, count, fill = 0)
weighted_fund_avg_df <- 
  section7BPrivateFundReporting %>%
  group_by(idCRD) %>%
  summarise_at(
    c(
      "amountFundMinimumInvestment",
      "pctFundManagerOwned",
      "pctFundFundOfFunds",
      "pctFundNonUSCitizens",
      "pctClientsFundInvestor"
    ),
    funs(weighted.mean(. , amountFundGrossAUM, na.rm = T))
  ) %>% 
  ungroup
office_count_df <- 
  managerOtherOfficeLocations %>% 
  group_by(idCRD) %>% 
  summarise(countOffices = max(countItem)) %>% 
  ungroup()
all_data <- 
  fund_totals %>% 
  left_join(
    vcs_in_location_df %>% select(idCRD, stateOfficePrimary)
  ) %>% 
  left_join(weighted_fund_avg_df) %>% 
  left_join(office_count_df) %>%
  left_join(service_provider_df) %>% 
  suppressMessages()

Scale the Data

set.seed(123) # make it reproducible
scaled_numeric_data <- 
  all_data %>%
  purrr::keep(is.numeric) %>% 
  mutate_all(as.numeric) %>% 
  gather(item, value, -idCRD) %>% 
  spread(item, value, fill = 0) %>% 
  dplyr::select(-idCRD) %>% 
  scale()
rownames(scaled_numeric_data) <-
  all_data$nameEntityManager
scaled_numeric_data %>% data.frame %>% rownames_to_column(var = 'nameEntityManager') %>% as_data_frame()

Perform the PCA

pc_funds <- 
  scaled_numeric_data %>% 
  prcomp()

Explore the Loadings

Now we can explore the results. If you aren’t familiar with the methodology behind PCA loadings I recommend reading this. Try to spend a few minutes exploring each of the 15 components and their variable loadings and think about what the scores may indicate. Try to focus on the top 5 components as they are the influential to explaining the variance of our data.

pc_funds$rotation %>% 
  data.frame() %>% 
  tibble::rownames_to_column(var = 'nameVariable') %>% 
  as_data_frame() %>% 
  arrange(PC1, PC2)

Visualize the Results

Now we will take the results, tidy them with broom package, and build an interactive plot of the top two principal components.

To create the data visualization we will first build a static ggplot2 scatter plot, customize the format, and then feed the static plot into plotly to produce an interactive visualization.

Note, in order to exactly replicate this visualization you must have the Myraid Pro font installed on your system which you can download from here.

If the code does not work I recommend removing code contained in hrbrmisc::theme_hrbrmstr_my() +. Finally please make sure you have the other required packages installed and loaded.

library(broom) # install.packages("broom")
library(ggplot2) # devtools::install_github("hadley/ggplot2") # requires dev version
library(plotly) # devtools::install_github("ropensci/plotly") requires dev version
library(hrbrmisc) # devtools::install_github("hrbrmstr/hrbrmisc")
pca_plot <- 
  augment(pc_funds, data = all_data) %>% # Tidy the results
  ggplot(aes(.fittedPC1, .fittedPC2, colour = stateOfficePrimary, text = nameEntityManager)) +
  geom_jitter(size = .55) + # jitter the results
  hrbrmisc::theme_hrbrmstr_my() + # require myriad pro font installed on your computer as well, remove this code if it doesn't work
  scale_x_continuous(name = "PC1 - AUM / Investor, Vehicle Count", breaks = seq(-13.5, 2.5, length.out = 8)) +
  scale_y_continuous(name = "PC2 - Feeder / Fund of Fund Reliance, Service Provider Complexity", 
                   breaks = seq(-7, 3, length.out = 8)) + 
  geom_hline(yintercept = 0, color = "gray70", size = .15) + # add horizontal line
  geom_vline(xintercept = 0, color = "gray70", size = .15) + ## add vertical line
  theme(panel.grid.major.x = element_blank(),panel.grid.major.y = element_blank()) + # remove the lines
  ggtitle("Venture Manager PCA Analysis")
pca_gg <-
  pca_plot %>% ggplotly()
pca_gg

Interpretting the Results

This visualization may like a standard scatter plot but it is not. The X and Y axis are unrelated and we aren’t looking to the x-axis to explain the y-axis. Each axis represents a distribution of component scores.

The x-axis represents the first principal component which, according to my interpretation of the PCA loadings represents the size of manager’s capital base, count of investors and the size of the manager’s operation. The farther to the left you move, the more assets under management, fund investors and offices the manager has. The farther to the right the less AUM, fund investors and offices a manager has.

To demonstrate this, hover over outliers farthest to the left, NEA and Deer Management, whose business name is actually Bessemer Ventures. These outliers encapsulate of first principal component. These managers have the largest assets under management and fund investor count, generally by an order of magnitude over the rest of the managers.

The y-axis represents the second principal component, this is more difficult to interpret. As you move south along the axis it indicates a heavy influence of having a prime broker, relying on fund of funds for capital and/or using feeder funds for a large portion of a vehicle’s capital. As you move south along the y-axis this indicates having a high number of unrelated fund auditors, administrators and marketers.

You can get a better understanding of this component by hovering over the outlier at the bottom right, FF Asset Management. They only have $144.812M in AUM which is why the firm is on the right on the x-axis and if you look at the all_data you will see the manager has engaged 6 different fund marketers and 3 separate fund auditors is why they are located on the south end of the y-axis. Compared to the other 218 managers, this count of fund marketers and auditors is a huge outlier. While this information doesn’t indicate anything in isolation, this heavy distortion does raise a red flag.

PCA Driven Conclussions

Finally we want to use this visualization and the results from our PCA to communicate feedback to the portfolio companies.

My first piece feedback is to be aware of meaning of NEA and Bessemer as relative whales. They have massive AUM and most likely will look to write significant large checks to optimize efficiency. Any pursuit of their capital should weight the importance of the overall round size and need for them to write a good-sized check.

My second piece of feedback is to treat any firm in the lower right quadrant with extreme skepticism. These managers have small asset bases and a fairly complex network of service providers. This indicates possible high reliance on fund of funds, a source of capital that adds another layer of fees to the end investor and may operate and push decisions onto the the recipient manager that pushes their own agenda.

This component also isolates managers with a higher count of auditors and administrators. This alone doesn’t indicate wrong doing but it does raises serious questions. I recommend before any dialogue with managers in that quadrant there is a serious vetting of these firms, their auditors, fund administrators and most importantly the principals and entities that own the manager.

That leaves the rest of the data, which if I were to guesstimate is about 200 of the 218 managers as candidates meet the criteria as a potential investor. I’d advocate a thorough exploration of the data in Section Schedule A and Section Schedule B which identifies the people and entities who own the management companies. I’d then write a function that takes the legal fund names and Googles for PDF files containing the name. Any matched results would provide us with a good idea of the fund’s financial returns and we may even find the fund’s portfolio investments and LPs. All very important information to process as you try to identify potential venture targets.

There are also 2 fantastic R data acquisition packages I’d integrate into the workflow. The first, rcrunchbase, wraps Crunchbase and is a fantastic way to discover a fund’s portfolio investments and any affiliations/investments of people affiliated with the firm.

The second is gdeltr2 which wraps The GDELT Project’s various APIs and data-stores. You can use this package to search for media or television references of the fund manager and/or any of its employees and portfolio companies. Depending on your R skills you could even right a cron job that queries hourly the API with a list of companies, terms, and people, storing any validated results in a separate database to build an on-going media tracking tool.

Parting Notes

I hope this tutorial was insightful and gave you an idea of how you can use fundManageR to try to answer real-life questions. I also hope it demonstrated how R can help you create powerful and engaging information in just a few lines of code.

I also wanted to encourage you to think about the importance of data driven, re-producible analysis. We have the ability to interactively show and share how we make decisions. Whether you are using R Notebooks or Jupyter Notebooks, it’s easy to create a data driven narrative that you can use to share, discuss and collaborate around a problem.

Thank you for investing your precious time going in going through this tutorial.

Don’t hesitate to reach out to me on twitter or via e-mail. I hope to be back soon with a tutorial integrating fundManageR, gdeltr2, and advanced machine learning techniques,

Stay curious, analytical, visual, open-minded, and away from spreadsheets.

LS0tCnRpdGxlOiAiRmluZCBNZSBhIFZlbnR1cmUgQ2FwaXRhbGlzdCIKYXV0aG9yOiAiQWxleCBCcmVzbGVyIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBjc3M6IH4vRGVza3RvcC9TZW1hbnRpYy1VSS9kaXN0L3NlbWFudGljLmNzcwogICAgZmlnX3dpZHRoOiAxMAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdGhlbWU6IGNvc21vCi0tLQo8YnI+CjxpbWcgc3JjID0iaHR0cDovL3dvbGZvZnlvcmtzdHJlZXQuY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE2LzA5L3ZlbnR1cmUtY2FwaXRhbC5qcGciPgoKIyMgSW50cm9kdWN0aW9uCgpUaGlzIHR1dG9yaWFsIGRlbW9uc3RyYXRlcyBob3cgSSBhbSB1dGlsaXppbmcgW2Z1bmRNYW5hZ2VSXShodHRwczovL2dpdGh1Yi5jb20vYWJyZXNsZXIvZnVuZE1hbmFnZVIpLCByZXByb2R1Y2libGUgcmVzZWFyY2gsIGRhdGEgdmlzdWFsaXphdGlvbiBhbmQgZGF0YSBzY2llbmNlIHRvIGFkdmlzZSB0d28gb2YgbXkgcG9ydGZvbGlvIGNvbXBhbmllcyB3aG8gYXJlIHByZXBhcmluZyBmb3IgYW4gaW5zdGl0dXRpb25hbCBmdW5kLXJhaXNpbmcgcm91bmQuICBUaGlzIGV4ZXJjaXNlIHdpbGwgZm9jdXMgb24gZXhwbG9yaW5nIGFuZCBhbmFseXppbmcgdmVudHVyZSBjYXBpdGFsaXN0cy4KCiMjIyBCdXQgQmVmb3JlIFdlIEdldCBTdGFydGVkCgpBY2N1cmF0ZSwgY2xlYW4sIGFuZCBbdGlkeV0oaHR0cDovL3I0ZHMuaGFkLmNvLm56L3RpZHktZGF0YS5odG1sKSBkYXRhIGlzIGFuIGluY3JlZGlibGUgcmVzb3VyY2UsIGJ1dCBpdCBpcyBvbmx5IGEgdG9vbC4gIAoKU3VjY2VzcyBpcyBhYm91dCBhIGNvbmZsdWVuY2Ugb2YgZmFjdG9ycyBpbmNsdWRpbmcsIGJ1dCBub3QgbGltaXRlZCB0bywgKmx1Y2sqLCAqZXhlY3V0aW9uKiwgKnBlcnNlcnZlcmVuY2UqLCAqY29tbXVuaWNhdGlvbiosIGFuZCBhICpjbGVhciosIGJ1dCAqZmxleGlibGUqLCB1bmRlcnN0YW5kaW5nIG9mIHRoZSBlbmQgZ29hbC4gIERhdGEsIGFuYWx5dGljYWwgc2tpbGxzLCBwcm9ncmFtbWluZyBhYmlsaXRpZXMsIGFuZCBtYWNoaW5lIGxlYXJuaW5nIHByb2ZpY2llbmN5IGFyZSBoaWdoIHBvd2VyZWQgd2VhcG9ucyBidXQgaW4gaXNvbGF0aW9uIHRoZXkgd29uJ3QgZ2V0IHlvdSB2ZXJ5IGZhcjsgdGhleSBhcmUgb25seSB0b29scy4KCk5vdywgbGV0J3MgZ2V0IHN0YXJ0ZWQKCiMjIyBUaGUgTWlzc2lvbjogSWRlbnRpZnkgYW5kIFRhcmdldCBWZW50dXJlIENhcGl0YWwgRmlybXMgSGVhZHF1YXJ0ZXJlZCBpbiBhIFNwZWNpZmllZCBBcmVhCgpUb2RheSdzIG1pc3Npb24gaXMgdG8gZmluZCB2ZW50dXJlIGNhcGl0YWxpc3RzIGhlYWQtcXVhcnRlcmVkIGluIE1hcnlsYW5kLCBXYXNoaW5ndG9uIEQuQy4sIFZpcmdpbmlhLCBOZXcgWW9yaywgTWFzc2FjaHVzZXR0cywgYW5kIEZsb3JpZGEuICBXZSBhcmUgbGltaXRpbmcgaXQgdG8gdGhlc2UgbG9jYXRpb25zIHRvIGZvY3VzIG9uIGFyZWFzIHRoYXQgbWUsIGFuZCB0aGUgcG9ydGZvbGlvIGNvbXBhbmllcyBoYXZlIHN0cm9uZyB0aWVzIGluLgoKVGhlIHdvcmtmbG93IGlzIHN0cmFpZ2h0IGZvcndhcmQ6IAoKKiBBY2Nlc3MgdGhlIG1vc3QgcmVjZW50IG1vbnRobHkgQURWIE1hbmFnZXIgc3VtbWFyeSBkYXRhIAoqIEV4Y2x1ZGUgbWFuYWdlcnMgb3V0c2lkZSBvZiBvdXIgc3BlY2lmaWVkIGxvY2F0aW9ucwoqIEV4Y2x1ZGUgYWxsIG5vbiB2ZW50dXJlIGV4ZW1wdCBtYW5hZ2VycwoqIEFjY2VzcyBkZXRhaWxlZCBtYW5hZ2VyIGRhdGEgYnkgcGlwaW5nIHRoZSBbQ1JEc10oIFtDUkQgSURzXShodHRwOi8vd3d3LmZpbnJhLm9yZy9pbmR1c3RyeS9jcmQpKSB0aHJvdWdoIHRoZSBgZ2V0X2RhdGFfYWR2X21hbmFnZXJzX2ZpbGluZ3NgIGZ1bmN0aW9uCiogRXhwbG9yZSB0aGUgZGF0YSAKKiBEcmF3IHNvbWUgY29uY2x1c2lvbnMuCgojIyMgSW1wb3J0YW50IENhdmVhdAoKVGhpcyBpcyBhIGNydWRlIGhhY2sgZm9yIGlzb2xhdGluZyB2ZW50dXJlIGNhcGl0YWxpc3RzLiAgQSBwdXJlIHBsYXkgdmVudHVyZSBmaXJtLCBpbiBtYW55IGNpcmN1bXN0YW5jZXMsIHV0aWxpemVzIGEgc3BlY2lhbCBleGVtcHRpb24gYWxsb3dpbmcgZm9yIHZlbnR1cmUgbWFuYWdlcnMgdG8gYXZvaWQgbWFueSBvZiB0aGUgc3RhbmRhcmQgcmVwb3J0aW5nIHJlcXVpcmVtZW50cyBtYW5kYXRlZCBvbiBTRUMgcmVndWxhdGVkIGludmVzdG1lbnQgbWFuYWdlcnMuIFRoZSBTRUMgY2FwdHVyZXMgaW5mb3JtYXRpb24gYW5kIGRpc2Nsb3NlcyBpdCBpbiBpdHMgc3RhbmRhcmQgbW9udGhseSByZXBvcnRpbmcgZGF0YSB2aWEgYSBsb2dpY2FsIGZpZWxkIHRoYXQgZGlzY2xvc2VzIHdoZXRoZXIgYSBtYW5hZ2VyIGhhcyB1dGlsaXplZCB0aGUgdmVudHVyZSBleGVtcHRpb24uCgpJdCBpcyBleHRyZW1lbHkgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCB0aGlzIG1ldGhvZCBsaW1pdHMgdXMgdG8gKm9ubHkqIHZlbnR1cmUgbWFuYWdlcnMgdXRpbGl6aW5nIHRoaXMgZXhlbXB0aW9uLiAgVGhpcyBtZXRob2Qgd29uJ3QgaGVscCB1cyBmaW5kIG1hbmFnZXJzIHdobyBoYXZlIHZlbnR1cmUgYXMgb25lIG9mIHRoZWlyIHByb2R1Y3QgbGluZXMsIGxpa2Ugc2F5IFtUZXhhcyBQYWNpZmljIEdyb3VwXShodHRwOi8vd3d3LnRwZy5jb20vKSwgb3IgYSB2ZW50dXJlIG1hbmFnZXIgdGhhdCBpcyByZWdpc3RlcmVkIGJ1dCBoYXNuJ3QgcXVhbGlmaWVkIG9yIGFwcGxpZWQgZm9yIHRoaXMgZXhlbXB0aW9uIGxpa2UgWzEzNyBWZW50dXJlc10oaHR0cDovLzEzN3ZlbnR1cmVzLmNvbS8pLgoKQ29udGV4dCBhbmQgY29tbW9uIHNlbnNlIGlzIGFzIGltcG9ydGFudCBhcyBhIHBvd2VyZnVsIGRhdGEgZHJpdmVuIHdvcmstZmxvdy4gVGhpcyB0dXRvcmlhbCBpcyBtZWFudCB0byBlbXBvd2VyIGJ1dCBub3QgbWlzbGVhZCB5b3UgaW50byB0aGlua2luZyB0aGUgcmVzdWx0cyBwcm9kdWNlZCBhcmUgYWxsLWVuY29tcGFzc2luZywgYmVjYXVzZSB0aGV5IGFyZSBub3QuICBXaGF0IHR1dG9yaWFsIHdpbGwgZG8gaXMgcHJvdmlkZSB5b3Ugd2l0aCBhIGNydWRlIG1ldGhvZCB0byBhY3F1aXJlIGRhdGEgdGhhdCB3ZSBrbm93IG1lZXQgdGhlIHZlbnR1cmUgY3JpdGVyaWEgd2UgZGVmaW5lZC4KCiMjIyBTdGVwIDEgLSBJbXBvcnQgTW9zdCBSZWNlbnQgTW9udGhseSBTdW1tYXJ5IEFEViBEYXRhCgpgYGB7ciBsb2FkX3BhY2thZ2VzX2ltcG9ydH0KcGFja2FnZXMgPC0KICBjKCdmdW5kTWFuYWdlUicsICdkcGx5cicsICdtYWdyaXR0cicsICd0aWR5cicsICdmb3JtYXR0YWJsZScsICd0aWJibGUnKSAjIHBhY2thZ2VzIHdlIG5lZWQKbGFwcGx5KHBhY2thZ2VzLCBsaWJyYXJ5LCBjaGFyYWN0ZXIub25seSA9IFQpCgphbGxfbWFuYWdlcnNfcmVjZW50IDwtIAogIGdldF9kYXRhX2Fkdl9tYW5hZ2Vyc19wZXJpb2RzX3N1bW1hcmllcyhhbGxfcGVyaW9kcyA9IEYsIG9ubHlfbW9zdF9yZWNlbnQgPSBULCBpc19leGVtcHQgPSBjKEYsIFQpLCBmaWxlX2RpcmVjdG9yeSA9IE5VTEwsIGZvbGRlcl9uYW1lID0gTlVMTCkKYGBgCgpXZSBub3cgaGF2ZSB0aGUgZGF0YSBmb3IgdGhlIDE1LDQ2MSBTRUMgcmVndWxhdGVkIG1hbmFnZXJzIHJlZ2lzdGVyZWQgYXMgb2YgT2N0b2JlciAzcmQsIDIwMTYgd2hpY2ggd2UgY2FuIHBhcmUgZG93biBhY2NvcmRpbmcgdG8gb3VyIHNlYXJjaCBjcml0ZXJpYS4KCiMjIyBTdGVwIDIgLSBGaW5kIEV4ZW1wdCBWZW50dXJlIE1hbmFnZXJzIGluIE91ciBUYXJnZXQgTG9jYXRpb25zCgpVc2luZyBgaGFzRXhlbXB0aW9uQXNTb2xlbHlWZW50dXJlQWR2aXNlcmAgYW5kIGBzdGF0ZU9mZmljZVByaW1hcnlgIGZpZWxkcyB3ZSBjYW4gcXVpY2tseSBmaWx0ZXIgZG93biBvdXIgZGF0YS4KCmBgYHtyIHBhcmVfZG93bn0KbG9jYXRpb25zIDwtIAogIGMoIkRDIiwgIk1BIiwgIlZBIiwgIkZMIiwgIk5ZIiwgIk1EIiwgIk5ZIikKCnZjc19pbl9sb2NhdGlvbl9kZiA8LSAKICBhbGxfbWFuYWdlcnNfcmVjZW50ICU+JQogIGRwbHlyOjpmaWx0ZXIoc3RhdGVPZmZpY2VQcmltYXJ5ICVpbiUgbG9jYXRpb25zLCAjIGNvbW1hIGFjdHMgYXMgQU5EIGluIGRwbHlyCiAgaGFzRXhlbXB0aW9uQXNTb2xlbHlWZW50dXJlQWR2aXNlciA9PSBUKQpgYGAKClRoZSBmaWx0ZXJlZCBkYXRhIGluY2x1ZGVzIHRoZSAyMTggcmVnaXN0ZXJlZCBtYW5hZ2VycyB0aGF0IG1lZXQgb3VyIHNlYXJjaCBjcml0ZXJpYS4gIFNvb24gd2Ugd2lsbCB0YWtlIHRoaXMgYW5kIHVzZSB0aGUgYGdldF9kYXRhX2Fkdl9tYW5hZ2Vyc19maWxpbmdzYCBmdW5jdGlvbiB0byBhY3F1aXJlIGFsbCB0aGUgZGlzY2xvc2VkIGluZm9ybWF0aW9uIGFib3V0IGVhY2ggb2YgdGhlc2UgbWFuYWdlcnMuCgpCZWZvcmUgZG9pbmcgdGhhdCBJIHdhbnQgdG8gaGlnaGxpZ2h0IHNvbWV0aGluZyB5b3Ugbm90aWNlIHdoaWxlIGV4cGxvcmluZyB0aGUgYHZjc19pbl9sb2NhdGlvbl9kZmAgZGF0YS4gIFNvbWUgb2YgdGhlIG1vc3QgcGVydGluZW50IGZpZWxkcyBjb250YWluaW5nIGluZm9ybWF0aW9uIGFib3V0IGEgbWFuYWdlcidzIGFzc2V0cyB1bmRlciBtYW5hZ2VtZW50LCBlbXBsb3llZSBjb3VudHMsIGNsaWVudCBjb3VudHMsIGZlZSBzdHJ1Y3R1cmVzIGFyZSBOQS4gIAoKVGhlIHZlbnR1cmUgZXhlbXB0aW9uIGFsbG93cyB0aGVzZSBtYW5hZ2VycyB0byBhdm9pZCB0aGUgcGVyaW9kaWMgcmVwb3J0aW5nIG9mIHRoaXMgaW5mb3JtYXRpb24sIHNvbWV0aGluZyBub24tZXhlbXB0IG1hbmFnZXJzIGFyZSBmb3JjZWQgdG8gZG8uICBUaGUgZ29vZCBuZXdzIGlzIHRoaXMgZGF0YSAqZG9lcyBleGlzdCogYW5kIGZ1bmRNYW5hZ2VSIHdpbGwgZ2V0IGl0IGZvciB5b3UsIHRoZSBkb3duc2lkZSBpcyB0aGUgZGF0YSBpcyByZXBvcnRlZCBhbm51YWxseSBhbmQgaXMgYnVyaWVkIGRlZXAgaW4gdGhlIG1lc3N5IGh0bWwgb2YgdGhlIG1hbmFnZXIncyBhY2NlcHRlZCBBRFYgZm9ybS4KCiMjIyBTdGVwIDMgLSBBY3F1aXJlIERldGFpbGVkIE1hbmFnZXIgRGF0YQoKVGhlIGBnZXRfZGF0YV9hZHZfbWFuYWdlcnNfZmlsaW5nc2AgZnVuY3Rpb24gcmVxdWlyZXMgZWl0aGVyIGZyZWUgdGV4dCBzZWFyY2ggbmFtZXMgb3IgbnVtZXJpYyBDUkRzIHRvIGFjcXVpcmUgdGhlIEFEViBmaWxpbmcgZGF0YS4gIFNlYXJjaCBuYW1lcyBtYXkgcHJvZHVjZSBsZXNzIGFjY3VyYXRlIHJlc3VsdHMsIGFuZCBvZnRlbiByZXR1cm4gbWFuYWdlcnMgd2hvc2UgaW5mb3JtYXRpb24gd2UgZGlkIG5vdCB3YW50LgoKQ1JEcyBhcmUgYSB1bmlxdWUgaWRlbnRpZmllciwgdGhlIFtwcmltYXJ5IGtleV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVW5pcXVlX2tleSkgb2YgdGhlIFNFQydzIElBUEQgZGF0YWJhc2UgZm9yIGFuIGVudGl0eSwgYW5kIGlmIHdlIGhhdmUgYSBmaXJtJ3MgQ1IgaXQgd2lsbCBhbHdheXMgcHJvZHVjZSBhY2N1cmF0ZSByZXN1bHRzLiAgT3VyIHByaW9yIHdvcmsgcHJvZHVjZWQgZWFjaCBtYW5hZ2VyJ3MgQ1JEIHdoaWNoIHdlIHdpbGwgdXNlIHRvIHBvd2VyIG91ciBuZXh0IGZ1bmN0aW9uIGNhbGwuCgojIyMgUGxlYXNlIEJlIFBhdGllbnQKClRoaXMgc2VhcmNoIHdpbGwgdGFrZSBhIHdoaWxlIGdpdmVuIHdlIGFyZSBwYXJzaW5nIDIxOCBtYW5hZ2VycyBzbyBiZSBwYXRpZW50LiAgVGhpcyBmdW5jdGlvbiB3aWxsIHByb2Nlc3MgYSBmZXcgKmdpZ2FieXRlcyogb2YgZGF0YSB0byBwcm9kdWNlIG91ciBmaW5hbCByZXN1bHRzLiBZb3UgY2FuIHRyYWNrIHRoZSBwcm9ncmVzcyB3aXRoIHRoZSBtZXNzYWdlIG91dHB1dCBidXQgSSdkIHJlY29tbWVuZCBkb2luZyBzb21ldGhpbmcgZWxzZSBmb3IgYWJvdXQgYW4gaG91ciBvciBzbyB3aGlsZSB0aGlzIHJ1bnMuCgpgYGB7ciBzZWFyY2hfY3Jkc30Kc2VhcmNoX2NyZHMgPC0gCiAgdmNzX2luX2xvY2F0aW9uX2RmJGlkQ1JEICMgY3JlYXRlIHZlY3RvciBvZiBDUkRzCmFsbF9tYW5hZ2VyX2RhdGEgPC0KICBnZXRfZGF0YV9hZHZfbWFuYWdlcnNfZmlsaW5ncygKICAgIGNyZF9pZHMgPSBzZWFyY2hfY3JkcywKICAgIGFsbF9zZWN0aW9ucyA9IFQsCiAgICBzZWFyY2hfbmFtZXMgPSBOVUxMLAogICAgYXNzaWduX3RvX2Vudmlvcm5tZW50ID0gVAogICkKYGBgCgojIyMgU3RlcCA0IC0gRXhwbG9yZSB0aGUgRGF0YQoKTm93IHRoYXQgd2UndmUgYWNxdWlyZWQgdGhlIGRhdGEgbGV0cyBleHBsb3JlIGl0IGFuZCBhbnN3ZXIgYSBmZXcgcXVlc3Rpb25zLgoKKiBXaGF0IGFyZSBlYWNoIG1hbmFnZXIncyByZXBvcnRlZCB0b3RhbCBhc3NldHMgdW5kZXIgbWFuYWdlbWVudD8KKiBXaGF0IGlzIHRoZSBkaXN0cmlidXRpb24gb2YgYXNzZXRzIHVuZGVyIG1hbmFnZW1lbnQgYnkgc3RhdGU/CiogSG93IG1hbnkgZnVuZCdzIGRvZXMgZWFjaCBtYW5hZ2VyIGNvbnRyb2w/CiogV2hhdCBjb25jbHVzaW9ucyBjYW4gd2UgZHJhdyBmcm9tIHRoZSBudW1lcmljIGRhdGEgYWJvdXQgdGhlIG1hbmFnZXJzPwoKCiMjIyBDYWxjdWxhdGUgQXNzZXRzIFVuZGVyIE1hbmFnZW1lbnQgYnkgTWFuYWdlcgoKVGhlIGZpcnN0IHRoaW5nIHdlIHdhbnQgdG8gZG8gaXMgY2FsY3VsYXRlIHRoZSBzdW1tYXJ5IGluZm9ybWF0aW9uIHdlJ2Qgbm9ybWFsbHkgZmluZCBpbiB0aGUgbW9udGhseSBBRFYgZGF0YSBmb3IgdGhlc2UgdmVudHVyZSBleGVtcHQgbWFuYWdlcnMuICAKCldlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBkYXRhIGluIHRoZSBgc2VjdGlvbjdCUHJpdmF0ZUZ1bmRSZXBvcnRpbmdgIHRhYmxlLiBXZSB3aWxsIHByb2R1Y2UgdGhlIGRlc2lyZWQgaW5mb3JtYXRpb24gYnkgZ3JvdXBpbmcgdGhlIGluZm9ybWF0aW9uIGJ5IENSRCBhbmQgbWFuYWdlciBuYW1lLCBhbmQgc3VtbWFyaXppbmcgdGhlIHRvdGFsIGFzc2V0cyB1bmRlciBtYW5hZ2VtZW50LCBjb3VudCBvZiBpbnZlc3RvcnMgYW5kIGNvdW50IG9mIGZ1bmQgdmVoaWNsZXMuICAKCkZpbmFsbHkgd2Ugd2lsbCBqb2luIHRoYXQgZGF0YSB3aXRoIGRlc2NyaXB0aXZlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBtYW5hZ2VyJ3Mgc3RhdGUgaGVhZHF1YXJ0ZXJzIGFuZCB3ZWJzaXRlLgoKYGBge3IgZ2V0X2Z1bmRfc2l6ZX0KZnVuZF9tYW5hZ2VyX3RvdGFscyA8LSAKICBzZWN0aW9uN0JQcml2YXRlRnVuZFJlcG9ydGluZyAlPiUgCiAgZ3JvdXBfYnkobmFtZUVudGl0eU1hbmFnZXIsIGlkQ1JEKSAlPiUgICMgc2V0IGdyb3VwCiAgc3VtbWFyaXNlKGFtb3VudEFVTVRvdGFsID0gc3VtKGFtb3VudEZ1bmRHcm9zc0FVTSwgbmEucm0gPSBUKSwKICAgICAgICAgY291bnRWZWhpY2xlcyA9IG4oKSwKICAgICAgICAgY291bnRJbnZlc3RvcnMgPSBzdW0oY291bnRGdW5kT3duZXJzLCBuYS5ybSA9IFQpKSAlPiUgCiAgbGVmdF9qb2luKAogICAgdmNzX2luX2xvY2F0aW9uX2RmICU+JSAgIyBqb2luIHRoZSBvZmZpY2Ugc3RhdGUKICAgICAgc2VsZWN0KGlkQ1JELCBzdGF0ZU9mZmljZVByaW1hcnkpCiAgKSAlPiUgCiAgbGVmdF9qb2luKAogICAgbWFuYWdlcldlYnNpdGUgJT4lICMgam9pbiB0aGUgbWFuYWdlciB3ZWJzaXRlCiAgICAgIGRwbHlyOjpzZWxlY3QoaWRDUkQsIHVybE1hbmFnZXIpCiAgKSAlPiUgCiAgc2VsZWN0KG5hbWVFbnRpdHlNYW5hZ2VyLCBpZENSRCwgdXJsTWFuYWdlciwgc3RhdGVPZmZpY2VQcmltYXJ5LCBldmVyeXRoaW5nKCkpICU+JSAKICB1bmdyb3VwKCkgJT4lICMgdW5ncm91cAogIGFycmFuZ2UoZGVzYyhhbW91bnRBVU1Ub3RhbCkpCmBgYAoKYGBge3IgcHJpdmF0ZV9mdW5kc30KZnVuZF9tYW5hZ2VyX3RvdGFscwpgYGAKCiMjIyBWZW50dXJlIE1hbmFnZXIgQnJlYWtkb3duIGJ5IExvY2F0aW9uCgpOZXh0IHdlIHdpbGwgdXNlIHRoZSBkYXRhIHRvIHBhaW50IGEgcGljdHVyZSBvZiB2ZW50dXJlIGxhbmRzY2FwZSBieSBsb2NhdGlvbi4gIFRvIG1ha2UgdGhpcyBpbmZvcm1hdGlvbiB2aXN1YWwgYW5kIGV4cGxvcmFibGUgSSB3aWxsIHNob3cgeW91IGhvdyB0byB1c2UgYW4gZXhwZXJpbWVudGFsIGZlYXR1cmUgb2YgdGhlIFtmb3JtYXR0YWJsZV0oaHR0cHM6Ly9naXRodWIuY29tL3Jlbmt1bi1rZW4vZm9ybWF0dGFibGUpIHBhY2thZ2Ugd2hpY2ggZW1iZWRzIFtodG1sd2lkZ2V0c10oaHRtbHdpZGdldHMub3JnKSBpbnRvIGEgdGFibGUuICAKCkluIG9yZGVyIGZvciB0aGlzIGNvZGUgdG8gd29yayB5b3UgbmVlZCB0byBoYXZlIHRoZSBwYWNrYWdlcyBsaXN0ZWQgYmVsb3cgbG9hZGVkLCB5b3UgY2FuIGZvbGxvdyB0aGUgaW5zdHJ1Y3Rpb25zIGluIHRoZSBjb2RlIGNvbW1lbnRzIHRvIGluc3RhbGwgdGhlbSBpZiB5b3UgaGF2ZSB5ZXQgdG8gZG8gc28uICBUaGUgZXhwZXJpbWVudGFsIGZvcm1hdHRhYmxlIGZ1bmN0aW9ucyBoYXZlIHlldCB0byBiZSBpbnRlZ3JhdGVkIGludG8gdGhlIHBhY2thZ2Ugc28gdGhlIGZ1bmN0aW9ucyBtdXN0IGJlIHNvdXJjZWQgZnJvbSBteSBnaXRodWIgZ2lzdC4KCmBgYHtyIHJlYWRfd2lkZ2V0X2NvZGV9CmxpYnJhcnkoc3BhcmtsaW5lKSAjZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJodG1sd2lkZ2V0cy9zcGFya2xpbmUiKQpsaWJyYXJ5KHNjYXR0ZXJEMykgIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImp1YmEvc2NhdHRlckQzIikKbGlicmFyeShodG1sd2lkZ2V0cykgIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInJhbW5hdGh2L2h0bWx3aWRnZXRzIikKc291cmNlKCJodHRwczovL2dpc3QuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2FicmVzbGVyLzgwODBhMDQ2Nzk0Zjk3YjhlMzE3NGI4NzFiODQyOWMwL3Jhdy8wNmY5YzY2NTUyNzc1ZmFjZGE3YWViN2U2NzgwZWQ3NGU5ZmRhMWMzL2h0bWx3aWRnZXRfdGVzdHMuciIpCmBgYAoKTm93IHdlIGNhbiBjcmVhdGUgdGhlIHRhYmxlLgoKVGhlIGZpcnN0IHN0ZXAgaXMgdG8gdXNlIGRwbHlyIHRvIGNyZWF0ZSB0aGUgc3VtbWFyeSBkYXRhLiAgV2UgZG8gdGhpcyBieSBncm91cGluZyBieSBzdGF0ZSwgcmVtb3ZpbmcgdGhlIENSRCBJRCwgYW5kIHVzaW5nIHRoZSBgc3VtbWFyaXNlX2lmYCBmdW5jdGlvbiB0byBxdWlja2x5IGNhbGN1bGF0ZSB0aGUgc3VtIG9mIGFsbCB0aGUgcmVtYWluaW5nIG51bWVyaWMgY29sdW1ucy4gIAoKTmV4dCwgd2Ugd2lsbCBzaG9ydGVuIHRoZSBjb2x1bW4gbmFtZXMgdG8gbWFrZSB0aGVtIGVhc2llciB0byBwcmludC4gV2UgYXJlIGxlZnQgd2l0aCB0aGUgY29yZSBzdW1tYXJ5IGRhdGEgYnkgc3RhdGUgYnV0IHN0aWxsIG5lZWQgdG8gYXVnbWVudCBpdCBieSBqb2luaW5nIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gYW5kIG91ciB2aXN1YWxpemF0aW9ucy4gIFdlIGRvbid0IGhhdmUgdGhlIGZ1bmQgbWFuYWdlciBjb3VudCBieSBzdGF0ZSBzbyB3ZSBjYW4gZGVyaXZlIHRoYXQgYW5kIGpvaW4gaXQgaW4gd2l0aCBvdXIgZXhpc3RpbmcgZGF0YS4gIEZpbmFsbHkgd2Ugd2lsbCBqb2luIG91ciB2aXN1YWxpemF0aW9uIGNvbHVtbnMsIHNjYXR0ZXIgcGxvdHMgb2YgYXNzZXRzIHVuZGVyIG1hbmFnZW1lbnQgYnkgZnVuZCB2ZWhpY2xlcyBhbmQgYXNzZXRzIHVuZGVyIG1hbmFnZW1lbnQgYnkgaW52ZXN0b3IgY291bnQuCgpgYGB7ciB0b3BfZnVuZF90YWJsZV93aWRnZXR9CmZ0X2xtIDwtCiAgZnVuZF9tYW5hZ2VyX3RvdGFscyAlPiUKICBkcGx5cjo6c2VsZWN0KC1pZENSRCkgJT4lCiAgZ3JvdXBfYnkoc3RhdGUgPSBzdGF0ZU9mZmljZVByaW1hcnkpICU+JQogIHN1bW1hcmlzZV9pZigucHJlZGljYXRlID0gaXMubnVtZXJpYywKICAgICAgICAgICAgICAgZnVucyguICU+JSBzdW0pKSAlPiUgCiAgcmVuYW1lKHZlaGljbGVzID0gY291bnRWZWhpY2xlcywgaW52ZXN0b3JzID0gY291bnRJbnZlc3RvcnMsIEFVTSA9IGFtb3VudEFVTVRvdGFsKSAlPiUKICBsZWZ0X2pvaW4oCiAgICBmdW5kX21hbmFnZXJfdG90YWxzICU+JQogICAgICBkcGx5cjo6c2VsZWN0KC1pZENSRCkgJT4lCiAgICAgIGdyb3VwX2J5KHN0YXRlID0gc3RhdGVPZmZpY2VQcmltYXJ5KSAlPiUKICAgICAgc3VtbWFyaXNlKG1hbmFnZXJzID0gbigpKQogICkgJT4lCiAgbGVmdF9qb2luKAogICAgZnVuZF9tYW5hZ2VyX3RvdGFscyAlPiUKICAgICAgZHBseXI6OnNlbGVjdCgtaWRDUkQpICU+JQogICAgICBncm91cF9ieShzdGF0ZSA9IHN0YXRlT2ZmaWNlUHJpbWFyeSkgJT4lCiAgICAgIHN1bW1hcml6ZSgKICAgICAgICBhdW1CeUZ1bmRDb3VudCA9IHNjYXR0ZXJfY2VsbCgKICAgICAgICAgIGNvdW50VmVoaWNsZXMsCiAgICAgICAgICBhbW91bnRBVU1Ub3RhbCAvIDEwMDAwMDAsICMjIGRpdmlkZSBieSAxTQogICAgICAgICAgeGxhYiA9ICJGdW5kIFZlaGljbGVzIiwKICAgICAgICAgIHlsYWIgPSAiQVVNIE1pbGxpb25zIiwKICAgICAgICAgIHRvb2x0aXBfdGV4dCA9IHBhc3RlMCgKICAgICAgICAgICAgbmFtZUVudGl0eU1hbmFnZXIsICMgQWRkIHRoZSB0b29sIHRpcAogICAgICAgICAgICAiPGJyPjxzdHJvbmc+QW1vdW50IEFVTTogPC9zdHJvbmc+IiwKICAgICAgICAgICAgYW1vdW50QVVNVG90YWwsCiAgICAgICAgICAgICI8YnI+PHN0cm9uZz5GdW5kIFZlaGljbGVzOiA8L3N0cm9uZz4iLAogICAgICAgICAgICBjb3VudFZlaGljbGVzCiAgICAgICAgICApLAogICAgICAgICAgcG9pbnRfc2l6ZSA9IDIwLCAjIG1vZGlmeSBwb2ludCBzaXplCiAgICAgICAgICBob3Zlcl9zaXplID0gNiwgIyBjaGFuZ2UgaG92ZXIgc2l6ZQogICAgICAgICAgZWxsaXBzZXMgPSBULCAjIGFkZCBncm91cGluZyBlbGxpcHNlCiAgICAgICAgICBob3Zlcl9vcGFjaXR5ID0gMSwgIyBjaGFuZ2UgaG92ZXIgb3BhY2l0eQogICAgICAgICAgaGVpZ2h0ID0gMjAwLCAjIG1vZGlmeSB0aGUgaGVpZ2h0CiAgICAgICAgICB3aWR0aCA9IDIyMCAjIG1vZGlmeSB0aGUgd2lkdGgKICAgICAgICApLAogICAgICAgIGF1bUJ5SW52ZXN0b3JDb3VudCA9IHNjYXR0ZXJfY2VsbCgKICAgICAgICAgIGNvdW50SW52ZXN0b3JzLAogICAgICAgICAgYW1vdW50QVVNVG90YWwgLyAxMDAwMDAwLAogICAgICAgICAgdG9vbHRpcF90ZXh0ID0gcGFzdGUwKAogICAgICAgICAgICBuYW1lRW50aXR5TWFuYWdlciwKICAgICAgICAgICAgIjxicj48c3Ryb25nPkFtb3VudCBBVU06PC9zdHJvbmc+IiwKICAgICAgICAgICAgYW1vdW50QVVNVG90YWwsCiAgICAgICAgICAgICI8YnI+PHN0cm9uZz5JbnZlc3RvciBUb3RhbDogPC9zdHJvbmc+IiwKICAgICAgICAgICAgY291bnRJbnZlc3RvcnMKICAgICAgICAgICksCiAgICAgICAgICB4bGFiID0gIkZ1bmQgSW52ZXN0b3JzIiwKICAgICAgICAgIHlsYWIgPSAiQVVNIE1pbGxpb25zIiwKICAgICAgICAgIHBvaW50X29wYWNpdHkgPSAwLjUsCiAgICAgICAgICBob3Zlcl9zaXplID0gNCwKICAgICAgICAgIGhvdmVyX29wYWNpdHkgPSAxLAogICAgICAgICAgcG9pbnRfc2l6ZSA9IDIwLAogICAgICAgICAgZWxsaXBzZXMgPSBULAogICAgICAgICAgY29sb3JzID0gIiNBOTQxNzUiLAogICAgICAgICAgaGVpZ2h0ID0gMjAwLAogICAgICAgICAgd2lkdGggPSAyNzAKICAgICAgICApCiAgICAgICkKICApICU+JQogIGZvcm1hdHRhYmxlKCkgJT4lCiAgYXMuaHRtbHdpZGdldCgpICU+JSAKICBzdXBwcmVzc01lc3NhZ2VzKCkKCgpmdF9sbSRkZXBlbmRlbmNpZXMgPC0gYyhmdF9sbSRkZXBlbmRlbmNpZXMsICMgc2V0dXAgdGhlIGh0bWx3aWRnZXQKICAgICAgICAgICAgICAgICAgICAgICAgaHRtbHdpZGdldHM6Ojp3aWRnZXRfZGVwZW5kZW5jaWVzKCJzY2F0dGVyRDMiLCAic2NhdHRlckQzIikpCmBgYAoKCiMjIyMgUHJpbnQgdGhlIFRhYmxlCgpJIGVuY291cmFnZSB5b3UgdG8gaG92ZXIgb3ZlciB0aGUgcG9pbnRzIHRvIHdoaWNoIHdpbGwgZ2l2ZSB5b3UgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgbWFuYWdlci4gIFlvdSBjYW4gYWxzbyBzY3JvbGwgaW4gYW5kIG91dCBvZiB0aGUgcGxvdHMgd2hpY2ggd2lsbCBzaG93IHlvdSBoZWxwIHlvdSBleHBsb3JlIGhpZ2ggbGV2ZWwgZGlzdHJpYnV0aW9ucyBhcyB5b3Ugc2Nyb2xsIG91dCBhbmQgZXhhY3QgeC15IGNvb3JkaW5hdGVzIGFzIHlvdSBzY3JvbGwgaW4uCgpgYGB7ciwgZmlnLndpZHRoPTEwfQpmdF9sbQpgYGAKCiMjIyBGdW5kIE1hbmFnZXIgRXhwbG9yYXRpb24KCk5leHQgd2Ugd2lsbCB0cnkgdG8gYmV0dGVyIHVuZGVyc3RhbmQgb3VyIGxpc3Qgb2YgbWFuYWdlcnMuICBXZSBhbHNvIHdhbnQgdG8gbWFrZSBpdCBlYXN5IHRvIG5hdmlnYXRlIHRvIHRoZSBtYW5hZ2VyJ3Mgd2VicGFnZSB3aGljaCB3ZSBjYW4gZG8gYnkgdGFraW5nIG91ciBkYXRhIGZyb20gc3RlcCAxIGFuZCBsYXllcmluZyBpbiBzb21lIGh0bWwuICBGaW5hbGx5LCB3ZSB3YW50IHRvIGFkZCBhIHZpc3VhbCBzcGFya2xpbmUgc2hvd2Nhc2luZyBhIG1hbmFnZXIncyBhc3NldHMgdW5kZXIgbWFuYWdlbWVudCBieSBmdW5kLCB3aGljaCAgd2lsbCBnaXZlIHVzIGEgZ29vZCB2aXN1YWwgY3VlIG9uIHRoZSBBVU0gdmFyaWFuY2UgYmV0d2VlbiBmdW5kcywgbnVtYmVyIG9mIGZ1bmRzIGFuZCBvdmVyYWxsIGZ1bmQgc2l6ZXMuCgpgYGB7ciBieV9tYW5hZ2VyX3RhYmxlfQptYW5hZ2VyX2RmIDwtCiAgZnVuZF9tYW5hZ2VyX3RvdGFscyAlPiUKICB1bmdyb3VwICU+JQogIGRwbHlyOjpzZWxlY3QoLWlkQ1JEKSAlPiUKICBtdXRhdGUodXJsTWFuYWdlciA9IGlmZWxzZSgKICAgIHVybE1hbmFnZXIgJT4lIGlzLm5hKCksCiAgICBOQSwKICAgIGxpc3QoCiAgICAgICI8YSBocmVmID0nIiwKICAgICAgdXJsTWFuYWdlciwgIyBjcmVhdGUgYSBjbGlja2FibGUgdXJsIHRoYXQgb3BlbnMgYSBuZXcgd2luZG93CiAgICAgICInIHRhcmdldCA9J19ibGFuayc+IiwKICAgICAgdXJsTWFuYWdlciwKICAgICAgIjwvYT4iCiAgICApICU+JSBpbnZva2UocGFzdGUwLCAuKQogICkpICU+JQogIGRwbHlyOjpyZW5hbWUoCiAgICB1cmwgPSB1cmxNYW5hZ2VyLCAjIGNoYW5nZSBuYW1pbmcgdG8gbWFrZSB0aGUgdGFibGUgZml0CiAgICBzdGF0ZSA9IHN0YXRlT2ZmaWNlUHJpbWFyeSwKICAgIGludmVzdG9ycyA9IGNvdW50SW52ZXN0b3JzLAogICAgdmVoaWNsZXMgPSBjb3VudFZlaGljbGVzLAogICAgQVVNID0gYW1vdW50QVVNVG90YWwKICApCgptYW5hZ2VyX2Z0IDwtCiAgZm9ybWF0dGFibGVXaXRoU0woCiAgICBUYWJsZURGID0gbWFuYWdlcl9kZiwKICAgIHJhd0RGID0KICAgICAgc2VjdGlvbjdCUHJpdmF0ZUZ1bmRSZXBvcnRpbmcgJT4lIAogICAgICBzZWxlY3QobmFtZUVudGl0eU1hbmFnZXIsIGZ1bmRBVU0gPSBhbW91bnRGdW5kR3Jvc3NBVU0pICU+JSAKICAgICAgZGF0YS5mcmFtZSgpLCAjIHJlcXVpcmVzIGRhdGEuZnJhbWUgdW5mb3J1dGFudGVseSAKICAgIGtleSA9ICJuYW1lRW50aXR5TWFuYWdlciIsICMga2V5IGZvciBzcGFyayBsaW5lCiAgICBTTGZpZWxkID0gImZ1bmRBVU0iICMgdmFyaWFibGUgdmlzdWFsaXplZCBpbiBzcGFyayBsaW5lCiAgKSAlPiUgCiAgc3VwcHJlc3NNZXNzYWdlcygpCmBgYAoKYGBge3IgbWFuYWdlcl9mdH0KbWFuYWdlcl9mdApgYGAKCiMjIyBBIERhdGEgRHJpdmVuIFZpZXcgb2YgdGhlIE1hbmFnZXIgTGFuZHNjYXBlCgpJbiB0aGlzIGZpbmFsIHN0ZXAgd2Ugd2lsbCB1dGlsaXplIHNvbWUgaW1wb3J0YW50IG51bWVyaWMgZGVzY3JpcHRvcnMgdG8gZHJhdyBzb21lIGNvbmNsdXNpb25zIGFib3V0IHRoZSBsYW5kc2NhcGUgb2Ygb3VyIG1hbmFnZXJzLiAgVG8gYWNoaWV2ZSB0aGlzIHdlIHdpbGwgdXNlIGEgc3RhdGlzdGljYWwgYW5hbHlzaXMgdG9vbCBrbm93biBhcyBbUHJpbmNpcGFsIENvbXBvbmVudHMgQW5hbHlzaXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1ByaW5jaXBhbF9jb21wb25lbnRfYW5hbHlzaXMpW1BDQV0uICAKClBDQSBpcyBhIHBvd2VyZnVsIHdheSB0byB0YWtlIG51bWVyaWMgZGF0YSBhbmQgYnJlYWsgaXQgZG93biBpbnRvIGEgc2V0IG9mIGNvbXBvbmVudHMgdGhhdCBleHBsYWluIHRoZSB2YXJpYW5jZSBvZiB0aGUgZGF0YS4gIFRoZSBhbGdvcml0aG0gcmV0dXJucyBhIHNldCBzY29yZXMgZm9yIGVhY2ggdGhlIHZhcmlhYmxlcy4gIFRoZXNlIHNjb3JlcyBpbmNsdWRlIGEgbGlzdCBvZiBjb21wb25lbnRzIHRoZSBsZW5ndGggb2YgdGhlIG51bWJlciBvZiB2YXJpYWJsZXMgdGhhdCBmdWxseSBleHBsYWluIHRoZSB2YXJpYW5jZS4gIFdlIHdpbGwgaXNvbGF0ZSwgZXhwbG9yZSBhbmQgdmlzdWFsaXplIHRoZSBmaXJzdCB0d28gcHJpbmNpcGFsIGNvbXBvbmVudHMuCgoKV2UgaGF2ZSBhc3NlbWJsZWQgc29tZSB1c2UgbnVtZXJpYyBkYXRhIGJ1dCB0aGVyZSBhcmUgYSBjb3VwbGUgb2Ygd2UgY2FuIGpvaW4gaW4gdG8gZW5oYW5jZSB0aGlzIGFuYWx5c2lzLiAgSW4gYWRkaXRpb24gdG8gdGhlIGFzc2V0cyB1bmRlciBtYW5hZ2VtZW50LCB2ZWhpY2xlIGNvdW50LCBhbmQgaW52ZXN0b3IgY291bnQgd2Ugd2FudCB0byBpbmNsdWRlIGluZm9ybWF0aW9uIHRoYXQgcHJveGllcyBhIGZpcm0ncyBvcGVyYXRpb25hbCBzaXplLCBzb21ldGhpbmcgd2UgY2FuIGdldCBieSBpbmNsdWRpbmcgYSBjb3VudCBvZiB0aGVpciBvZmZpY2VzLiAgV2UgYWxzbyB3YW50IHRvIGluY2x1ZGUgaW5mb3JtYXRpb24gYSBtYW5hZ2VyJ3MgYXZlcmFnZSBmdW5kIHByb2ZpbGUsIHNvbWV0aGluZyB3ZSBjYW4gZG8gYnkgam9pbmluZyBpbiBpbmZvcm1hdGlvbiBhYm91dCBhIG1hbmFnZXIncyB3ZWlnaHRlZCBhdmVyYWdlIGludmVzdG1lbnQgbWluaW11bSBhbmQgcGVyY2VudGFnZSBicmVha2Rvd24gb2YgdmFyaW91cyBmdW5kIGNoYXJhY3RlcmlzdGljcyB7cGVyY2VudCBvZiBpbnRlcm5hdGlvbmFsIGludmVzdG9ycywgcGVyY2VudCBmcm9tIGZ1bmQgb2YgZnVuZHMsIHBlcmNlbnQgZnJvbSBmZWVkZXIgZnVuZCwgZXRjLi59LiAgRmluYWxseSB3ZSB3YW50IGluZm9ybWF0aW9uIHRoYXQgcHJvZmlsZXMgYSBtYW5hZ2VyJ3MgZGVwdGggb2YgcmVsYXRpb25zaGlwcyB3aXRoICBzZXJ2aWNlcyBwcm92aWRlcnMuICBXZSBjYW4gYWNoaWV2ZSB0aGlzIGJ5IGpvaW5pbmcgaW4gYSBjb3VudCBvZiB0aGUgc2VydmljZSBwcm92aWRlcnMgYnkgc2VydmljZSBhbHNvIGRpc2Nsb3NlZCBpbiBzZWN0aW9uN0JQcml2YXRlRnVuZFJlcG9ydGluZy4KCk9uY2UgY29tcGxldGVkLCB3ZSB3aWxsIHRha2UgdGhlIGRhdGEsIGlzb2xhdGUgdGhlIHRoZSBudW1lcmljIGZpZWxkcywgc2NhbGUgdG8gbWVhbiB6ZXJvIGFuZCB1c2UgYHByY29tcGAgZnVuY3Rpb24gdG8gYXBwbHkgdGhlIHByaW5jaXBhbCBjb21wb25lbnRzIGFsZ29yaXRobS4gIFdlIHdpbGwgdGhlbiBleHBsb3JlIHRoZSBsb2FkaW5nIHNjb3JlcywgdmlzdWFsaXplIHRoZSByZXN1bHQgZmlyc3QgdHdvIGNvbXBvbmVudHMgYW5kIGRyYXcgc29tZSBjb25jbHVzaW9ucyBmcm9tIHRoZSBkYXRhLgoKIyMjIEFzc2VtYmxlIERhdGEgZm9yIFBDQQoKYGBge3IgcGNhX3ByZXB9CmZ1bmRfdG90YWxzIDwtIAogIHNlY3Rpb243QlByaXZhdGVGdW5kUmVwb3J0aW5nICU+JQogIGdyb3VwX2J5KGlkQ1JELCBuYW1lRW50aXR5TWFuYWdlcikgJT4lCiAgc3VtbWFyaXNlKAogICAgY291bnRGdW5kcyA9IG1heChudW1iZXJGdW5kKSwKICAgIGFtb3VudFRvdGFsQVVNID0gc3VtKGFtb3VudEZ1bmRHcm9zc0FVTSwgbmEucm0gPSBUKSwKICAgIGNvdW50VG90YWxGdW5kT3duZXJzID0gc3VtKGNvdW50RnVuZE93bmVycywgbmEucm0gPSBUKQogICkgJT4lCiAgdW5ncm91cAoKc2VydmljZV9wcm92aWRlcl9kZiA8LSAKICBzZWN0aW9uN0JQcml2YXRlRnVuZFJlcG9ydGluZyAlPiUgCiAgc2VsZWN0KGlkQ1JELCBtYXRjaGVzKCJebmFtZVtBLVpdIikpICU+JSAKICBzZWxlY3QoLWMobmFtZUZ1bmQsIG5hbWVGdW5kR1BNYW5hZ2VyVHJ1c3RlZURpcmVjdG9yLCBuYW1lRnVuZEZlZWRlckdQTWFuYWdlclRydXN0ZWVEaXJlY3RvcikpICU+JSAKICBzZWxlY3QoLW1hdGNoZXMoIm5hbWVGdW5kRmVlZGVyR1BNYW5hZ2VyVHJ1c3RlZURpcmVjdG9yfG5hbWVDdXN0b2RpYW5CdXNpbmVzc3xFbnRpdHlNYW5hZ2VyIikpICU+JSAKICBnYXRoZXIoaXRlbSwgdmFsdWUsIC1jKGlkQ1JEKSwgbmEucm0gPSBUKSAlPiUgCiAgbXV0YXRlKGl0ZW0gPSBpdGVtICU+JSBzdHJfcmVwbGFjZV9hbGwoIlswLTldIiwgJycpKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoaWRDUkQsIGl0ZW0pICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICBtdXRhdGUoaXRlbSA9IGl0ZW0gJT4lIHN0cl9yZXBsYWNlX2FsbCgnbmFtZScsICdjb3VudEZ1bmQnKSkgJT4lCiAgc3ByZWFkKGl0ZW0sIGNvdW50LCBmaWxsID0gMCkKCndlaWdodGVkX2Z1bmRfYXZnX2RmIDwtIAogIHNlY3Rpb243QlByaXZhdGVGdW5kUmVwb3J0aW5nICU+JQogIGdyb3VwX2J5KGlkQ1JEKSAlPiUKICBzdW1tYXJpc2VfYXQoCiAgICBjKAogICAgICAiYW1vdW50RnVuZE1pbmltdW1JbnZlc3RtZW50IiwKICAgICAgInBjdEZ1bmRNYW5hZ2VyT3duZWQiLAogICAgICAicGN0RnVuZEZ1bmRPZkZ1bmRzIiwKICAgICAgInBjdEZ1bmROb25VU0NpdGl6ZW5zIiwKICAgICAgInBjdENsaWVudHNGdW5kSW52ZXN0b3IiCiAgICApLAogICAgZnVucyh3ZWlnaHRlZC5tZWFuKC4gLCBhbW91bnRGdW5kR3Jvc3NBVU0sIG5hLnJtID0gVCkpCiAgKSAlPiUgCiAgdW5ncm91cAoKb2ZmaWNlX2NvdW50X2RmIDwtIAogIG1hbmFnZXJPdGhlck9mZmljZUxvY2F0aW9ucyAlPiUgCiAgZ3JvdXBfYnkoaWRDUkQpICU+JSAKICBzdW1tYXJpc2UoY291bnRPZmZpY2VzID0gbWF4KGNvdW50SXRlbSkpICU+JSAKICB1bmdyb3VwKCkKCmFsbF9kYXRhIDwtIAogIGZ1bmRfdG90YWxzICU+JSAKICBsZWZ0X2pvaW4oCiAgICB2Y3NfaW5fbG9jYXRpb25fZGYgJT4lIHNlbGVjdChpZENSRCwgc3RhdGVPZmZpY2VQcmltYXJ5KQogICkgJT4lIAogIGxlZnRfam9pbih3ZWlnaHRlZF9mdW5kX2F2Z19kZikgJT4lIAogIGxlZnRfam9pbihvZmZpY2VfY291bnRfZGYpICU+JQogIGxlZnRfam9pbihzZXJ2aWNlX3Byb3ZpZGVyX2RmKSAlPiUgCiAgc3VwcHJlc3NNZXNzYWdlcygpCmBgYAoKIyMjIFNjYWxlIHRoZSBEYXRhCgpgYGB7ciBzY2FsZV90aGUgZGF0YX0Kc2V0LnNlZWQoMTIzKSAjIG1ha2UgaXQgcmVwcm9kdWNpYmxlCgpzY2FsZWRfbnVtZXJpY19kYXRhIDwtIAogIGFsbF9kYXRhICU+JQogIHB1cnJyOjprZWVwKGlzLm51bWVyaWMpICU+JSAKICBtdXRhdGVfYWxsKGFzLm51bWVyaWMpICU+JSAKICBnYXRoZXIoaXRlbSwgdmFsdWUsIC1pZENSRCkgJT4lIAogIHNwcmVhZChpdGVtLCB2YWx1ZSwgZmlsbCA9IDApICU+JSAKICBkcGx5cjo6c2VsZWN0KC1pZENSRCkgJT4lIAogIHNjYWxlKCkKcm93bmFtZXMoc2NhbGVkX251bWVyaWNfZGF0YSkgPC0KICBhbGxfZGF0YSRuYW1lRW50aXR5TWFuYWdlcgoKc2NhbGVkX251bWVyaWNfZGF0YSAlPiUgZGF0YS5mcmFtZSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICduYW1lRW50aXR5TWFuYWdlcicpICU+JSBhc19kYXRhX2ZyYW1lKCkKYGBgCgojIyMgUGVyZm9ybSB0aGUgUENBCgpgYGB7ciBwY2FfY2FsY30KcGNfZnVuZHMgPC0gCiAgc2NhbGVkX251bWVyaWNfZGF0YSAlPiUgCiAgcHJjb21wKCkKYGBgCgojIyMgRXhwbG9yZSB0aGUgTG9hZGluZ3MKCk5vdyB3ZSBjYW4gZXhwbG9yZSB0aGUgcmVzdWx0cy4gIElmIHlvdSBhcmVuJ3QgZmFtaWxpYXIgd2l0aCB0aGUgbWV0aG9kb2xvZ3kgYmVoaW5kIFBDQSBsb2FkaW5ncyBJIHJlY29tbWVuZCBbcmVhZGluZyB0aGlzXShodHRwOi8vc3RhdHMuc3RhY2tleGNoYW5nZS5jb20vcXVlc3Rpb25zLzIyMi93aGF0LWFyZS1wcmluY2lwYWwtY29tcG9uZW50LXNjb3JlcykuICBUcnkgdG8gc3BlbmQgYSBmZXcgbWludXRlcyBleHBsb3JpbmcgZWFjaCBvZiB0aGUgMTUgY29tcG9uZW50cyBhbmQgdGhlaXIgdmFyaWFibGUgbG9hZGluZ3MgYW5kIHRoaW5rIGFib3V0IHdoYXQgdGhlIHNjb3JlcyBtYXkgaW5kaWNhdGUuICBUcnkgdG8gZm9jdXMgb24gdGhlIHRvcCA1IGNvbXBvbmVudHMgYXMgdGhleSBhcmUgdGhlIGluZmx1ZW50aWFsIHRvIGV4cGxhaW5pbmcgdGhlIHZhcmlhbmNlIG9mIG91ciBkYXRhLgoKYGBge3IgcGNhX2xvYWRpbmdzfQpwY19mdW5kcyRyb3RhdGlvbiAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAnbmFtZVZhcmlhYmxlJykgJT4lIAogIGFzX2RhdGFfZnJhbWUoKSAlPiUgCiAgYXJyYW5nZShQQzEsIFBDMikKYGBgCgoKIyMjIFZpc3VhbGl6ZSB0aGUgUmVzdWx0cwoKTm93IHdlIHdpbGwgdGFrZSB0aGUgcmVzdWx0cywgdGlkeSB0aGVtIHdpdGggW2Jyb29tXShodHRwczovL2dpdGh1Yi5jb20vZGdydHdvL2Jyb29tKSBwYWNrYWdlLCBhbmQgYnVpbGQgYW4gaW50ZXJhY3RpdmUgcGxvdCBvZiB0aGUgdG9wIHR3byBwcmluY2lwYWwgY29tcG9uZW50cy4gIAoKVG8gY3JlYXRlIHRoZSBkYXRhIHZpc3VhbGl6YXRpb24gd2Ugd2lsbCBmaXJzdCBidWlsZCBhIHN0YXRpYyBbZ2dwbG90Ml0oaHR0cHM6Ly9naXRodWIuY29tL2hhZGxleS9nZ3Bsb3QyKSBzY2F0dGVyIHBsb3QsIGN1c3RvbWl6ZSB0aGUgZm9ybWF0LCBhbmQgdGhlbiBmZWVkIHRoZSBzdGF0aWMgcGxvdCBpbnRvIFtwbG90bHldKGh0dHBzOi8vcGxvdC5seS8pIHRvIHByb2R1Y2UgYW4gaW50ZXJhY3RpdmUgdmlzdWFsaXphdGlvbi4KCk5vdGUsIGluIG9yZGVyIHRvIGV4YWN0bHkgcmVwbGljYXRlIHRoaXMgdmlzdWFsaXphdGlvbiB5b3UgbXVzdCBoYXZlIHRoZSBNeXJhaWQgUHJvIGZvbnQgaW5zdGFsbGVkIG9uIHlvdXIgc3lzdGVtIHdoaWNoIHlvdSBjYW4gZG93bmxvYWQgZnJvbSBbaGVyZV0oaHR0cDovL2ZvbnRzdXAuY29tL2ZhbWlseS9teXJpYWQrcHJvLmh0bWwpLiAgCgpJZiB0aGUgY29kZSBkb2VzIG5vdCB3b3JrIEkgcmVjb21tZW5kIHJlbW92aW5nIGNvZGUgY29udGFpbmVkIGluICBgaHJicm1pc2M6OnRoZW1lX2hyYnJtc3RyX215KCkgK2AuICBGaW5hbGx5IHBsZWFzZSBtYWtlIHN1cmUgeW91IGhhdmUgdGhlIG90aGVyIHJlcXVpcmVkIHBhY2thZ2VzIGluc3RhbGxlZCBhbmQgbG9hZGVkLgoKYGBge3IgcGNhX3Bsb3RfcHJlcH0KbGlicmFyeShicm9vbSkgIyBpbnN0YWxsLnBhY2thZ2VzKCJicm9vbSIpCmxpYnJhcnkoZ2dwbG90MikgIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImhhZGxleS9nZ3Bsb3QyIikgIyByZXF1aXJlcyBkZXYgdmVyc2lvbgpsaWJyYXJ5KHBsb3RseSkgIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInJvcGVuc2NpL3Bsb3RseSIpIHJlcXVpcmVzIGRldiB2ZXJzaW9uCmxpYnJhcnkoaHJicm1pc2MpICMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJocmJybXN0ci9ocmJybWlzYyIpCgpwY2FfcGxvdCA8LSAKICBhdWdtZW50KHBjX2Z1bmRzLCBkYXRhID0gYWxsX2RhdGEpICU+JSAjIFRpZHkgdGhlIHJlc3VsdHMKICBnZ3Bsb3QoYWVzKC5maXR0ZWRQQzEsIC5maXR0ZWRQQzIsIGNvbG91ciA9IHN0YXRlT2ZmaWNlUHJpbWFyeSwgdGV4dCA9IG5hbWVFbnRpdHlNYW5hZ2VyKSkgKwogIGdlb21faml0dGVyKHNpemUgPSAuNTUpICsgIyBqaXR0ZXIgdGhlIHJlc3VsdHMKICBocmJybWlzYzo6dGhlbWVfaHJicm1zdHJfbXkoKSArICMgcmVxdWlyZSBteXJpYWQgcHJvIGZvbnQgaW5zdGFsbGVkIG9uIHlvdXIgY29tcHV0ZXIgYXMgd2VsbCwgcmVtb3ZlIHRoaXMgY29kZSBpZiBpdCBkb2Vzbid0IHdvcmsKICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJQQzEgLSBBVU0gLyBJbnZlc3RvciwgVmVoaWNsZSBDb3VudCIsIGJyZWFrcyA9IHNlcSgtMTMuNSwgMi41LCBsZW5ndGgub3V0ID0gOCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJQQzIgLSBGZWVkZXIgLyBGdW5kIG9mIEZ1bmQgUmVsaWFuY2UsIFNlcnZpY2UgUHJvdmlkZXIgQ29tcGxleGl0eSIsIAogICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC03LCAzLCBsZW5ndGgub3V0ID0gOCkpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZ3JheTcwIiwgc2l6ZSA9IC4xNSkgKyAjIGFkZCBob3Jpem9udGFsIGxpbmUKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJncmF5NzAiLCBzaXplID0gLjE1KSArICMjIGFkZCB2ZXJ0aWNhbCBsaW5lCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAjIHJlbW92ZSB0aGUgbGluZXMKICBnZ3RpdGxlKCJWZW50dXJlIE1hbmFnZXIgUENBIEFuYWx5c2lzIikKcGNhX2dnIDwtCiAgcGNhX3Bsb3QgJT4lIGdncGxvdGx5KCkKYGBgCgpgYGB7ciBwY2FfcGxvdCwgZmlnLndpZHRoPTl9CnBjYV9nZwpgYGAKCiMjIyMgSW50ZXJwcmV0dGluZyB0aGUgUmVzdWx0cwoKVGhpcyB2aXN1YWxpemF0aW9uIG1heSBsaWtlIGEgc3RhbmRhcmQgc2NhdHRlciBwbG90IGJ1dCBpdCBpcyBub3QuICBUaGUgWCBhbmQgWSBheGlzIGFyZSB1bnJlbGF0ZWQgYW5kIHdlIGFyZW4ndCBsb29raW5nIHRvIHRoZSB4LWF4aXMgdG8gZXhwbGFpbiB0aGUgeS1heGlzLiAgRWFjaCBheGlzIHJlcHJlc2VudHMgYSBkaXN0cmlidXRpb24gb2YgY29tcG9uZW50IHNjb3Jlcy4KClRoZSB4LWF4aXMgcmVwcmVzZW50cyB0aGUgZmlyc3QgcHJpbmNpcGFsIGNvbXBvbmVudCB3aGljaCwgYWNjb3JkaW5nIHRvIG15IGludGVycHJldGF0aW9uIG9mIHRoZSBQQ0EgbG9hZGluZ3MgcmVwcmVzZW50cyB0aGUgc2l6ZSBvZiBtYW5hZ2VyJ3MgY2FwaXRhbCBiYXNlLCBjb3VudCBvZiBpbnZlc3RvcnMgYW5kIHRoZSBzaXplIG9mIHRoZSBtYW5hZ2VyJ3Mgb3BlcmF0aW9uLiAgVGhlIGZhcnRoZXIgdG8gdGhlIGxlZnQgeW91IG1vdmUsIHRoZSBtb3JlIGFzc2V0cyB1bmRlciBtYW5hZ2VtZW50LCBmdW5kIGludmVzdG9ycyBhbmQgb2ZmaWNlcyB0aGUgbWFuYWdlciBoYXMuICBUaGUgZmFydGhlciB0byB0aGUgcmlnaHQgdGhlIGxlc3MgQVVNLCBmdW5kIGludmVzdG9ycyBhbmQgb2ZmaWNlcyBhIG1hbmFnZXIgaGFzLgoKVG8gZGVtb25zdHJhdGUgdGhpcywgaG92ZXIgb3ZlciBvdXRsaWVycyBmYXJ0aGVzdCB0byB0aGUgbGVmdCwgW05FQV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTmV3X0VudGVycHJpc2VfQXNzb2NpYXRlcykgYW5kIERlZXIgTWFuYWdlbWVudCwgd2hvc2UgYnVzaW5lc3MgbmFtZSBpcyBhY3R1YWxseSBbQmVzc2VtZXIgVmVudHVyZXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Jlc3NlbWVyX1ZlbnR1cmVfUGFydG5lcnMpLiAgVGhlc2Ugb3V0bGllcnMgZW5jYXBzdWxhdGUgb2YgZmlyc3QgcHJpbmNpcGFsIGNvbXBvbmVudC4gIFRoZXNlIG1hbmFnZXJzIGhhdmUgdGhlIGxhcmdlc3QgYXNzZXRzIHVuZGVyIG1hbmFnZW1lbnQgYW5kIGZ1bmQgaW52ZXN0b3IgY291bnQsIGdlbmVyYWxseSBieSBhbiBvcmRlciBvZiBtYWduaXR1ZGUgb3ZlciB0aGUgcmVzdCBvZiB0aGUgbWFuYWdlcnMuCgpUaGUgeS1heGlzIHJlcHJlc2VudHMgdGhlIHNlY29uZCBwcmluY2lwYWwgY29tcG9uZW50LCB0aGlzIGlzIG1vcmUgZGlmZmljdWx0IHRvIGludGVycHJldC4gIEFzIHlvdSBtb3ZlIHNvdXRoIGFsb25nIHRoZSBheGlzIGl0IGluZGljYXRlcyBhIGhlYXZ5IGluZmx1ZW5jZSBvZiBoYXZpbmcgYSBbcHJpbWUgYnJva2VyXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QcmltZV9icm9rZXJhZ2UpLCByZWx5aW5nIG9uIFtmdW5kIG9mIGZ1bmRzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9GdW5kX29mX2Z1bmRzKSBmb3IgY2FwaXRhbCBhbmQvb3IgdXNpbmcgW2ZlZWRlciBmdW5kc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRmVlZGVyX2Z1bmQpIGZvciBhIGxhcmdlIHBvcnRpb24gb2YgYSB2ZWhpY2xlJ3MgY2FwaXRhbC4gIEFzIHlvdSBtb3ZlIHNvdXRoIGFsb25nIHRoZSB5LWF4aXMgdGhpcyBpbmRpY2F0ZXMgaGF2aW5nIGEgaGlnaCBudW1iZXIgb2YgdW5yZWxhdGVkIGZ1bmQgYXVkaXRvcnMsIGFkbWluaXN0cmF0b3JzIGFuZCBtYXJrZXRlcnMuICAKCllvdSBjYW4gZ2V0IGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgdGhpcyBjb21wb25lbnQgYnkgaG92ZXJpbmcgb3ZlciB0aGUgb3V0bGllciBhdCB0aGUgYm90dG9tIHJpZ2h0LCBGRiBBc3NldCBNYW5hZ2VtZW50LiAgVGhleSBvbmx5IGhhdmUgJDE0NC44MTJNIGluIEFVTSB3aGljaCBpcyB3aHkgdGhlIGZpcm0gaXMgb24gdGhlIHJpZ2h0IG9uIHRoZSB4LWF4aXMgYW5kIGlmIHlvdSBsb29rIGF0IHRoZSBgYWxsX2RhdGFgIHlvdSB3aWxsIHNlZSB0aGUgbWFuYWdlciBoYXMgZW5nYWdlZCA2IGRpZmZlcmVudCBmdW5kIG1hcmtldGVycyBhbmQgMyBzZXBhcmF0ZSBmdW5kIGF1ZGl0b3JzIGlzIHdoeSB0aGV5IGFyZSBsb2NhdGVkIG9uIHRoZSBzb3V0aCBlbmQgb2YgdGhlIHktYXhpcy4gICBDb21wYXJlZCB0byB0aGUgb3RoZXIgMjE4IG1hbmFnZXJzLCB0aGlzIGNvdW50IG9mIGZ1bmQgbWFya2V0ZXJzIGFuZCBhdWRpdG9ycyBpcyBhICpodWdlKiBvdXRsaWVyLiAgV2hpbGUgdGhpcyBpbmZvcm1hdGlvbiBkb2Vzbid0IGluZGljYXRlIGFueXRoaW5nIGluIGlzb2xhdGlvbiwgdGhpcyBoZWF2eSBkaXN0b3J0aW9uIGRvZXMgcmFpc2UgYSByZWQgZmxhZy4KCiMjIyBQQ0EgRHJpdmVuIENvbmNsdXNzaW9ucwoKRmluYWxseSB3ZSB3YW50IHRvIHVzZSB0aGlzIHZpc3VhbGl6YXRpb24gYW5kIHRoZSByZXN1bHRzIGZyb20gb3VyIFBDQSB0byBjb21tdW5pY2F0ZSBmZWVkYmFjayB0byB0aGUgcG9ydGZvbGlvIGNvbXBhbmllcy4KCk15IGZpcnN0IHBpZWNlIGZlZWRiYWNrIGlzIHRvIGJlIGF3YXJlIG9mIG1lYW5pbmcgb2YgTkVBIGFuZCBCZXNzZW1lciBhcyByZWxhdGl2ZSB3aGFsZXMuICBUaGV5IGhhdmUgbWFzc2l2ZSBBVU0gYW5kIG1vc3QgbGlrZWx5IHdpbGwgbG9vayB0byB3cml0ZSBzaWduaWZpY2FudCBsYXJnZSBjaGVja3MgdG8gb3B0aW1pemUgZWZmaWNpZW5jeS4gQW55IHB1cnN1aXQgb2YgdGhlaXIgY2FwaXRhbCBzaG91bGQgd2VpZ2h0IHRoZSBpbXBvcnRhbmNlIG9mIHRoZSBvdmVyYWxsIHJvdW5kIHNpemUgYW5kIG5lZWQgZm9yIHRoZW0gdG8gd3JpdGUgYSBnb29kLXNpemVkIGNoZWNrLgoKTXkgc2Vjb25kIHBpZWNlIG9mIGZlZWRiYWNrIGlzIHRvIHRyZWF0IGFueSBmaXJtIGluIHRoZSBsb3dlciByaWdodCBxdWFkcmFudCB3aXRoIGV4dHJlbWUgc2tlcHRpY2lzbS4gIFRoZXNlIG1hbmFnZXJzIGhhdmUgc21hbGwgYXNzZXQgYmFzZXMgYW5kIGEgZmFpcmx5IGNvbXBsZXggbmV0d29yayBvZiBzZXJ2aWNlIHByb3ZpZGVycy4gIFRoaXMgaW5kaWNhdGVzIHBvc3NpYmxlIGhpZ2ggcmVsaWFuY2Ugb24gZnVuZCBvZiBmdW5kcywgYSBzb3VyY2Ugb2YgY2FwaXRhbCB0aGF0IGFkZHMgYW5vdGhlciBsYXllciBvZiBmZWVzIHRvIHRoZSBlbmQgaW52ZXN0b3IgYW5kIG1heSBvcGVyYXRlIGFuZCBwdXNoIGRlY2lzaW9ucyBvbnRvIHRoZSB0aGUgcmVjaXBpZW50IG1hbmFnZXIgdGhhdCBwdXNoZXMgdGhlaXIgb3duIGFnZW5kYS4gIAoKVGhpcyBjb21wb25lbnQgYWxzbyBpc29sYXRlcyBtYW5hZ2VycyB3aXRoIGEgaGlnaGVyIGNvdW50IG9mIGF1ZGl0b3JzIGFuZCBhZG1pbmlzdHJhdG9ycy4gIFRoaXMgYWxvbmUgZG9lc24ndCBpbmRpY2F0ZSB3cm9uZyBkb2luZyBidXQgaXQgZG9lcyByYWlzZXMgc2VyaW91cyBxdWVzdGlvbnMuICBJIHJlY29tbWVuZCBiZWZvcmUgYW55IGRpYWxvZ3VlIHdpdGggbWFuYWdlcnMgaW4gdGhhdCBxdWFkcmFudCB0aGVyZSBpcyBhIHNlcmlvdXMgdmV0dGluZyBvZiB0aGVzZSBmaXJtcywgdGhlaXIgYXVkaXRvcnMsIGZ1bmQgYWRtaW5pc3RyYXRvcnMgYW5kIG1vc3QgaW1wb3J0YW50bHkgdGhlIHByaW5jaXBhbHMgYW5kIGVudGl0aWVzIHRoYXQgb3duIHRoZSBtYW5hZ2VyLgoKVGhhdCBsZWF2ZXMgdGhlIHJlc3Qgb2YgdGhlIGRhdGEsIHdoaWNoIGlmIEkgd2VyZSB0byBndWVzc3RpbWF0ZSBpcyBhYm91dCAyMDAgb2YgdGhlIDIxOCBtYW5hZ2VycyBhcyBjYW5kaWRhdGVzIG1lZXQgdGhlIGNyaXRlcmlhIGFzIGEgcG90ZW50aWFsIGludmVzdG9yLiAgSSdkIGFkdm9jYXRlIGEgdGhvcm91Z2ggZXhwbG9yYXRpb24gb2YgdGhlIGRhdGEgaW4gU2VjdGlvbiBTY2hlZHVsZSBBIGFuZCBTZWN0aW9uIFNjaGVkdWxlIEIgd2hpY2ggaWRlbnRpZmllcyB0aGUgcGVvcGxlIGFuZCBlbnRpdGllcyB3aG8gb3duIHRoZSBtYW5hZ2VtZW50IGNvbXBhbmllcy4gIEknZCB0aGVuIHdyaXRlIGEgZnVuY3Rpb24gdGhhdCB0YWtlcyB0aGUgbGVnYWwgZnVuZCBuYW1lcyBhbmQgR29vZ2xlcyBmb3IgUERGIGZpbGVzIGNvbnRhaW5pbmcgdGhlIG5hbWUuICBBbnkgbWF0Y2hlZCByZXN1bHRzIHdvdWxkIHByb3ZpZGUgdXMgd2l0aCBhIGdvb2QgaWRlYSBvZiB0aGUgZnVuZCdzIGZpbmFuY2lhbCByZXR1cm5zIGFuZCB3ZSBtYXkgZXZlbiBmaW5kIHRoZSBmdW5kJ3MgcG9ydGZvbGlvIGludmVzdG1lbnRzIGFuZCBMUHMuICBBbGwgdmVyeSBpbXBvcnRhbnQgaW5mb3JtYXRpb24gdG8gcHJvY2VzcyBhcyB5b3UgdHJ5IHRvIGlkZW50aWZ5IHBvdGVudGlhbCB2ZW50dXJlIHRhcmdldHMuIAoKVGhlcmUgYXJlIGFsc28gMiBmYW50YXN0aWMgUiBkYXRhIGFjcXVpc2l0aW9uIHBhY2thZ2VzIEknZCBpbnRlZ3JhdGUgaW50byB0aGUgd29ya2Zsb3cuICBUaGUgZmlyc3QsIFtyY3J1bmNoYmFzZV0oaHR0cHM6Ly9naXRodWIuY29tL3RhcmFrYzAyL3JjcnVuY2hiYXNlKSwgd3JhcHMgW0NydW5jaGJhc2VdKGh0dHBzOi8vd3d3LmNydW5jaGJhc2UuY29tLykgYW5kIGlzIGEgZmFudGFzdGljIHdheSB0byBkaXNjb3ZlciBhIGZ1bmQncyBwb3J0Zm9saW8gaW52ZXN0bWVudHMgYW5kIGFueSBhZmZpbGlhdGlvbnMvaW52ZXN0bWVudHMgb2YgcGVvcGxlIGFmZmlsaWF0ZWQgd2l0aCB0aGUgZmlybS4gIAoKVGhlIHNlY29uZCBpcyBbZ2RlbHRyMl0oaHR0cHM6Ly9naXRodWIuY29tL2FicmVzbGVyL2dkZWx0cjIpIHdoaWNoIHdyYXBzICBbVGhlIEdERUxUIFByb2plY3RdKGdkZWx0cHJvamVjdC5vcmcpJ3MgdmFyaW91cyBBUElzIGFuZCBkYXRhLXN0b3Jlcy4gIFlvdSBjYW4gdXNlIHRoaXMgcGFja2FnZSB0byBzZWFyY2ggZm9yIG1lZGlhIG9yIHRlbGV2aXNpb24gcmVmZXJlbmNlcyBvZiB0aGUgZnVuZCBtYW5hZ2VyIGFuZC9vciBhbnkgb2YgaXRzIGVtcGxveWVlcyBhbmQgcG9ydGZvbGlvIGNvbXBhbmllcy4gIERlcGVuZGluZyBvbiB5b3VyIFIgc2tpbGxzIHlvdSBjb3VsZCBldmVuIHJpZ2h0IGEgW2Nyb24gam9iXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Dcm9uKSB0aGF0IHF1ZXJpZXMgaG91cmx5IHRoZSBBUEkgd2l0aCBhIGxpc3Qgb2YgY29tcGFuaWVzLCB0ZXJtcywgYW5kIHBlb3BsZSwgc3RvcmluZyBhbnkgdmFsaWRhdGVkIHJlc3VsdHMgaW4gYSBzZXBhcmF0ZSBkYXRhYmFzZSB0byBidWlsZCBhbiBvbi1nb2luZyBtZWRpYSB0cmFja2luZyB0b29sLgoKIyMjIFBhcnRpbmcgTm90ZXMKCkkgaG9wZSB0aGlzIHR1dG9yaWFsIHdhcyBpbnNpZ2h0ZnVsIGFuZCBnYXZlIHlvdSBhbiBpZGVhIG9mIGhvdyB5b3UgY2FuIHVzZSBmdW5kTWFuYWdlUiB0byB0cnkgdG8gYW5zd2VyIHJlYWwtbGlmZSBxdWVzdGlvbnMuICBJIGFsc28gaG9wZSBpdCBkZW1vbnN0cmF0ZWQgaG93IFIgY2FuIGhlbHAgeW91IGNyZWF0ZSBwb3dlcmZ1bCBhbmQgZW5nYWdpbmcgaW5mb3JtYXRpb24gaW4ganVzdCBhIGZldyBsaW5lcyBvZiBjb2RlLiAgCgpJIGFsc28gd2FudGVkIHRvIGVuY291cmFnZSB5b3UgdG8gdGhpbmsgYWJvdXQgdGhlIGltcG9ydGFuY2Ugb2YgZGF0YSBkcml2ZW4sIHJlLXByb2R1Y2libGUgYW5hbHlzaXMuICBXZSBoYXZlIHRoZSBhYmlsaXR5IHRvIGludGVyYWN0aXZlbHkgc2hvdyBhbmQgc2hhcmUgaG93IHdlIG1ha2UgZGVjaXNpb25zLiAgV2hldGhlciB5b3UgYXJlIHVzaW5nIFtSIE5vdGVib29rc10oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9yX25vdGVib29rcy5odG1sKSBvciBbSnVweXRlciBOb3RlYm9va3NdKGp1cHl0ZXIub3JnKSwgaXQncyBlYXN5IHRvIGNyZWF0ZSBhIGRhdGEgZHJpdmVuIG5hcnJhdGl2ZSB0aGF0IHlvdSBjYW4gdXNlIHRvIHNoYXJlLCBkaXNjdXNzIGFuZCBjb2xsYWJvcmF0ZSBhcm91bmQgYSBwcm9ibGVtLgoKVGhhbmsgeW91IGZvciBpbnZlc3RpbmcgeW91ciBwcmVjaW91cyB0aW1lIGdvaW5nIGluIGdvaW5nIHRocm91Z2ggdGhpcyB0dXRvcmlhbC4gCgpEb24ndCBoZXNpdGF0ZSB0byByZWFjaCBvdXQgdG8gbWUgb24gW3R3aXR0ZXJdKGh0dHBzOi8vdHdpdHRlci5jb20vYWJyZXNsZXIpIG9yIHZpYSBlLW1haWwuICBJIGhvcGUgdG8gYmUgYmFjayAgc29vbiB3aXRoIGEgdHV0b3JpYWwgaW50ZWdyYXRpbmcgZnVuZE1hbmFnZVIsIGdkZWx0cjIsIGFuZCBhZHZhbmNlZCBtYWNoaW5lIGxlYXJuaW5nIHRlY2huaXF1ZXMsCgpTdGF5IGN1cmlvdXMsIGFuYWx5dGljYWwsIHZpc3VhbCwgb3Blbi1taW5kZWQsIGFuZCBhd2F5IGZyb20gc3ByZWFkc2hlZXRzLg==