Introduction

Transportation is currently the United States’ largest source of greenhouse gas emissions, and transportation-sector electrification is widely recognized as one of the best strategies for significantly reducing these emissions. Invented as early as mid-19th century, electric vehicles (EVs) have become the modern society’s choice to reduce carbon emissions and promote sustainable growth. Recent years have witnessed a rapid rising trend of global EV growth.

In the US, EV registrations reached record market share of 1.8% in 2020. Regionally, the New York City’s share of 2% is driving the Northeast. According to their 2020 Renewables on the Rise report, New York State ranks #2 in the United States for EV sold and available EV charging infrastructure, having more than 53,000 registered EVs on the road and an estimated 1,750 public EV charging stations.

Using New York State as an example, our project aims to analyze the historical trend and current status of the EV market, and predict the future image of EV industry. Specifically, our project consists of 3 parts: first, we analyze the historical trend of the EV industry in New York State, together with the contributing factors. Second, we map the current distribution of EV registration and charging stations in New York State at county level. Finally, we employ sentiment analysis and LDA model analysis to explore customer’s needs and expectation about EV.

Part 1: Exploring the development of EV market and major factors

In this part, we’ll visualize the historical development of EVs in New York State and analyze the major drivers for the rapid growth. First, We’ll start by providing a historical overview of the EV registration.

The rapid growth of EV registration in New York State

xl_data <- "EV-Registration-Tables.xlsx"

EV_time <- read_excel(path=xl_data, sheet=5)

EV_time <- head(EV_time, -1)

EV_time <- mutate(EV_time, Time=paste(`Month Name`, stri_sub(EV_time$Year, 3,4), sep=" '"))


p1 <- EV_time %>%
  group_by("Year") %>%
  hchart(., "area", hcaes(x = `Time`, y=cumsum(`Total EVs`)))%>%  
  hc_title(text = "Original EV Registration in New York State (2011-2019)") %>%
  hc_subtitle(text = "Source: New York State Energy Research and Development Authority") %>%
  hc_yAxis(title = list(text="Cumulative sum of EV"))
p1

The above graph shows the cumulative number of EV registration in New York State since 2011. EV registration has grown 100 times between December 2011 to December 2015, and has maintained a steady growth rate up till now. New Yorkers have demonstrated strong interest for EVs over time.

Major drivers of New York State EV growth

Next, we’ll explore several key driving factors of rapid EV growth in New York State.

1st factor: growing population

The population of New York State has maintained a growing pace during the first half of 2010s. Hence, this creates more demand for auto industry including EV.

population <- read_excel("ny_pop.xlsx")
p3 <- ggplot(population, aes(x=year, y=cumsum(total_population/1000000), text=paste("Year: ", year,
 "<br>cumulative population (Millions): ", cumsum(total_population/1000000)))) + geom_bar(stat="identity",alpha=.6, width=0.8, fill= "#0882c7")+labs(title = "New York State Cumulative Population",subtitle = "Source: U.S. Census Bureau", x="Year",y="Cumulative population (in millions)")+
         theme_classic()+
   theme(plot.title = element_text(size = 12, face = "bold"),
         axis.title.x = element_text(size = 10),
          axis.title.y = element_text(size = 10))+
  scale_x_continuous(breaks = c(2010, 2011,2012,2013,2014,2015,2016,2017,2018,2019), labels = c("2010", "2011","2012", "2013","2014", "2015", "2016", "2017", "2018", "2019"))

ggplotly(p3, tooltip="text")

2nd factor: Carbon emission reduction and policy support

During the past 3 decades, gasoline and diesel remain as the top 2 sources of greeenhouse emissions under the transportation sector in the U.S.. Hence, New York State has issued a package of policies to accelerate the electrification trend in transportation. For example, New York State is one of the first states in the U.S. to sign a Zero Emission Vehicle Memorandum of Understanding (ZEV MOU) to enact policies that will ensure the deployment of 3.3 million light-duty ZEVs by 2025. Furthermore, under New York State’s Charge NY initiative, electric vehicle buyers can receive a rebate of up to 2,000 for new car purchases or leases, together with a Federal Tax Credit of up to 7,500. In addition, automotive manufacfurers are offering more EV models for consumers to choose, ranging from cost-effective to luxury EV.

Therefore, policy support and the increasing variety of EVs make it a good timing for consumers to purchase EV.

emission <- read_excel("ny_emission.xlsx")
p4 <- ggplot(emission, aes(fill=type, y=inventory, x=as.factor(year), text=paste("Year: ", as.factor(year),
                                                                                            "<br>Emissions inventory: ", inventory,
                                                                                            "<br>Type: ", type)))+
  geom_bar(position="dodge", stat="identity",alpha=.6, width=0.8) +
         labs(title = "Transportation Sector Greenhouse Emissions Inventory, 1990–2016",subtitle = "Source: New York State Energy Research and Development Authority", x="Year",y="Emissions Inventory (MMtCO2e)")+
         theme_bw()+
   theme(plot.title = element_text(size = 10, face = "bold"),
         axis.title.x = element_text(size = 9),
          axis.title.y = element_text(size = 9))

3rd factor: Increasing number and variety of EV models offered

Due to the boost of design and battery technology, nowadays automotive manufacturers are offering various kinds of EV to the consumers. It is estimated that the number of battery electric (BEV) and plug-in hybrid (PHEV) passenger vehicle models available to U.S. consumers will increase from 60 to 83 between 2020 and 2022. Meanwhile, numerous manufacturers have publicly signaled their investment plans and commitments to a future of electric vehicle.

In addition, EVs have become more affordable because of dramatic reductions in the cost of batteries. The cost of battery packs has fallen from approximately $1,000/kilowatt-hour (kWh) in 2010 to approximately $156/kWh in 2019. These factors all contribute to the growth of EV sales.

EV_make <- read_excel(path=xl_data, sheet=3)
EV_make <- head(EV_make, -1)
EV_make <- mutate(EV_make, Name=paste(Make, Model))

p5 <- EV_make %>%
  hchart("treemap", hcaes(x='Name', value= 'Registrations', color= 'Registrations')) %>%
           hc_title(text = "EV make-models in New York State by popularity") %>%
           hc_subtitle(text = "Source: New York State Energy Research and Development Authority")
p5

The above treemap shows the great variety of EV models in the current U.S. market. There are 66 EV models (PHEV and BEV) by 32 automotive manufacturers available to U.S. consumers. Tesla Model 3 and Toyota Prius Prime enjoy the predominant popularity among U.S. consumer, followed by Tesla Model S, Chevrolet Volt, Ford Fusion Energi, and Tesla Model X.

In addition, U.S consumers prefer domestic car brands (Tesla, Chevrolet, Ford) the most, followed by Japanese brand (Toyota, Honda, and Nissan). Except for the two luxury EV models from Tesla (Model S and Model X), 8 out of the top 10 popular EVs are under $50,000 (MSRP). It suggests that affordability and energy efficiency are the key factors when it comes to EV purchase for New York consumers.

metric = read_excel("ev_info.xlsx")
p6 <- ggplot(metric,aes(x = range, y = MSRP/1000, label=type))+
  #geom_point(aes(size = cost_per_mile),alpha=.6)+
  geom_text(aes(color=factor(brand)), alpha = 0.6, vjust=-0.2, check_overlap=TRUE, size=3.5)+
  labs(title = "Features of EV by Make-models", subtitle = "Source: Visual Capitalist", x="Range On a Single Charge(mile)",y="Manufacturer's Suggested Retail Price($k)")+ geom_label()+theme_bw()+
  theme(plot.title = element_text(size = 12, face = "bold"),
         axis.title.x = element_text(size = 9),
          axis.title.y = element_text(size = 9))
ggplotly(p6)

The above graph offers more detailed make-models information of the current EV market in the U.S.. In terms of affordability, there are six EV models available for under $50,000 (MSRP) with a driving range of up to 250 miles. Specifically, EV models by Japanese carmakers (Nissan, Hyundai) emphasis the most on affordability. All of the 5 EV models by Japanese manufacturers are under $40,000 (MSRP). There will be even more models with a net cost of under $50,000 when current federal, state, and rebates are factored in.

Part 2: mapping the locations of EV charging stations in New York State

In this part, we’ll map the current distribution of EV registration and charging stations in New York State, to examine whether charging stations would affect EV sales in the NY State. The assumption is that the number of charging stations is positively associated with EV sales. Both EV charging station and registration data are downloaded from New York State Energy Research and Development Authority, and were updated in 2021.

charging <- read.csv("EV_Charging_Stations.csv")

charging1 <-charging %>%
  select(City, ZIP, Latitude, Longitude,EV.Connector.Types, Access.Days.Time)
  
m <- leaflet(charging1) %>%
  addTiles('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png')%>%
     setView(-75.3167, 43.09287, zoom = 6)


content <- paste("City name:",charging1$City,"<br/>",
                 "Zipcode:", charging1$ZIP,"<br/>",
                 "EV Connector Types:",charging1$EV.Connector.Types,"<br/>",
                 "Access Days Time:", charging1$Access.Days.Time, "<br/>")


m2 <- m %>% addCircles(popup = content)

mclust <- m2 %>% addCircleMarkers(popup=content, clusterOptions = markerClusterOptions())
mclust

From the above map, the coverage rate of EV charging stations in New York State is pretty high. Charging stations are mostly distributed in the southeast New York. The clusters of EV charging stations are significantly correlated with population density, where bigger cities have more charging stations. New York City has the most charging stations, followed by other large cities such as Albany, Buffalo, Rochester, Yonkers, and Syracuse. Next, let’s further explore the distribution within NYC.

nybb <- readOGR("nybb_21a", layer="nybb")
## OGR data source with driver: ESRI Shapefile 
## Source: "/Users/christinalv/DataScience_Assignments/Data Visualization/nybb_21a", layer: "nybb"
## with 5 features
## It has 4 fields
charging2 <- charging1 %>%
  filter(City %in% c("New York", "Bronx", "Queens", "Brooklyn", "Staten Island", "Long Island City"))%>%
  rename(BoroName = City)

charging2$BoroName <- as.character(charging2$BoroName)
charging2$BoroName[charging2$BoroName == "New York"] <- "Manhattan"
charging2$BoroName[charging2$BoroName == "Long Island City"] <- "Queens"


charging3 <- charging2 %>%
  select(BoroName) %>%
  group_by(BoroName) %>%
  add_count(BoroName) %>%
  distinct()

nybb$number_of_charging <- charging3$n

p7 <- tm_shape(nybb) + tm_fill("number_of_charging", title="Density of charging stations in NYC", style="pretty") +
  tm_borders(alpha=0.5)+tm_style("white")

p7

The above map is a heatmap of the distribution of EV charging stations in New York City. There are 326 EV charging stations in Manhattan, followed by 75 in Brooklyn, 21 in Queens, 19 in Staten Island, and 14 in Bronx. New Yorkers don’t need to worry about charging their EVs in Manhattan since the borough has the most charging stations available in the state.

nyzip = read_excel("ny_zipcode.xlsx")

nyzip <- nyzip %>%
  select(Zip, Latitude, Longitude)

nyzip$Zip <- as.character(nyzip$Zip)
  


EV_registration <- read_excel(path=xl_data, sheet=2)
EV_registration <- head(EV_registration, -1)
EV_registration <- EV_registration %>% rename(Zip = `ZIP Code`)

total <- left_join(nyzip, EV_registration, by=("Zip"))
total[is.na(total)] <- 0

mm <- leaflet(total) %>%
  addTiles('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png')%>%
     setView(-75.3167, 43.09287, zoom = 6)

content2 <- paste("Zipcode:", total$Zip,"<br/>",
                 "Number of PHEV/EREV:",total$`PHEV/EREV`,"<br/>",
                 "Number of BEV:", total$BEV, "<br/>",
                 "Total EVs:", total$`Total EVs`, "<br/>")

m3 <- mm %>% addCircles(popup = content2)

mclust2 <- m3 %>% addCircleMarkers(popup=content2, clusterOptions = markerClusterOptions())

mclust2

The above map displays the distribution of EV registration in New York State by zipcode. The data is downloaded from New York State Energy Research and Development Authority and is updated in 2021. EV registration seems to be roughly even distributed throughout NY state at first glance. EVs are mostly distributed in the Southeast New York, which is the same pattern as shown in the map of charging stations.

Comparing the two maps, EV-charging station ratio is pretty high in Northeast and central NY, where more EVs are registrated but with fewer charging stations. By contrast, EV-charging station ratio is lowest in New York City.

LS0tCnRpdGxlOiAiV2hhdCBNYWtlcyBhbiBFbGVjdHJpYyBWZWhpY2xlIFdpbj8iCmF1dGhvcnM6ICJXYW55aW5nIExpLCBZdW54dWFuIENoZW4sIFRhb3RhbyBKaWFuZywgSmlhIFlpbmcgTHYiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgaGlnaGxpZ2h0OiB0YW5nbwogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdGhlbWU6IGpvdXJuYWwKICBpb3NsaWRlc19wcmVzZW50YXRpb246CiAgICBzbWFsbGVyOiB5ZXMKICAgIGtlZXBfbWQ6IHRydWUKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIGRmX3ByaW50OiBrYWJsZQp1cmxjb2xvcjogcmVkCmZvbnQtZmFtaWx5OiBIZWx2ZXRpY2EKYXV0b3NpemU6IHllcwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGNhY2hlID0gVCwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGLCBjYWNoZS5sYXp5ID0gRikKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoc3RyaW5naSkKbGlicmFyeShoaWdoY2hhcnRlcikKbGlicmFyeShnZ21hcCkKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KHJnZGFsKQpsaWJyYXJ5KHRtYXApCmxpYnJhcnkocmdkYWwpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkocnZlc3QpICAgICAKbGlicmFyeShzdHJpbmdyKSAKbGlicmFyeShOTFApCmxpYnJhcnkodG0pCmxpYnJhcnkoY29sb3JSYW1wcykKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGdncGxvdDIpICAgIApsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoRFQpCmxpYnJhcnkoY29sb3JzcGFjZSkKYGBgCgoKCgojIyMgKipJbnRyb2R1Y3Rpb24qKgpUcmFuc3BvcnRhdGlvbiBpcyBjdXJyZW50bHkgdGhlIFVuaXRlZCBTdGF0ZXPigJkgbGFyZ2VzdCBzb3VyY2Ugb2YgZ3JlZW5ob3VzZSBnYXMgZW1pc3Npb25zLCBhbmQgdHJhbnNwb3J0YXRpb24tc2VjdG9yIGVsZWN0cmlmaWNhdGlvbiBpcyB3aWRlbHkgcmVjb2duaXplZCBhcyBvbmUgb2YgdGhlIGJlc3Qgc3RyYXRlZ2llcyBmb3Igc2lnbmlmaWNhbnRseSByZWR1Y2luZyB0aGVzZSBlbWlzc2lvbnMuIEludmVudGVkIGFzIGVhcmx5IGFzIG1pZC0xOXRoIGNlbnR1cnksIGVsZWN0cmljIHZlaGljbGVzIChFVnMpIGhhdmUgYmVjb21lIHRoZSBtb2Rlcm4gc29jaWV0eSdzIGNob2ljZSB0byByZWR1Y2UgY2FyYm9uIGVtaXNzaW9ucyBhbmQgcHJvbW90ZSBzdXN0YWluYWJsZSBncm93dGguIFJlY2VudCB5ZWFycyBoYXZlIHdpdG5lc3NlZCBhIHJhcGlkIHJpc2luZyB0cmVuZCBvZiBnbG9iYWwgRVYgZ3Jvd3RoLiAKCkluIHRoZSBVUywgRVYgcmVnaXN0cmF0aW9ucyByZWFjaGVkIHJlY29yZCBtYXJrZXQgc2hhcmUgb2YgMS44JSBpbiAyMDIwLiBSZWdpb25hbGx5LCB0aGUgTmV3IFlvcmsgQ2l0eSdzIHNoYXJlIG9mIDIlIGlzIGRyaXZpbmcgdGhlIE5vcnRoZWFzdC4gQWNjb3JkaW5nIHRvIHRoZWlyIDIwMjAgUmVuZXdhYmxlcyBvbiB0aGUgUmlzZSByZXBvcnQsIE5ldyBZb3JrIFN0YXRlIHJhbmtzICMyIGluIHRoZSBVbml0ZWQgU3RhdGVzIGZvciBFViBzb2xkIGFuZCBhdmFpbGFibGUgRVYgY2hhcmdpbmcgaW5mcmFzdHJ1Y3R1cmUsIGhhdmluZyBtb3JlIHRoYW4gNTMsMDAwIHJlZ2lzdGVyZWQgRVZzIG9uIHRoZSByb2FkIGFuZCBhbiBlc3RpbWF0ZWQgMSw3NTAgcHVibGljIEVWIGNoYXJnaW5nIHN0YXRpb25zLgoKVXNpbmcgTmV3IFlvcmsgU3RhdGUgYXMgYW4gZXhhbXBsZSwgb3VyIHByb2plY3QgYWltcyB0byBhbmFseXplIHRoZSBoaXN0b3JpY2FsIHRyZW5kIGFuZCBjdXJyZW50IHN0YXR1cyBvZiB0aGUgRVYgbWFya2V0LCBhbmQgcHJlZGljdCB0aGUgZnV0dXJlIGltYWdlIG9mIEVWIGluZHVzdHJ5LiBTcGVjaWZpY2FsbHksIG91ciBwcm9qZWN0IGNvbnNpc3RzIG9mIDMgcGFydHM6IGZpcnN0LCB3ZSBhbmFseXplIHRoZSBoaXN0b3JpY2FsIHRyZW5kIG9mIHRoZSBFViBpbmR1c3RyeSBpbiBOZXcgWW9yayBTdGF0ZSwgdG9nZXRoZXIgd2l0aCB0aGUgY29udHJpYnV0aW5nIGZhY3RvcnMuIFNlY29uZCwgd2UgbWFwIHRoZSBjdXJyZW50IGRpc3RyaWJ1dGlvbiBvZiBFViByZWdpc3RyYXRpb24gYW5kIGNoYXJnaW5nIHN0YXRpb25zIGluIE5ldyBZb3JrIFN0YXRlIGF0IGNvdW50eSBsZXZlbC4gRmluYWxseSwgd2UgZW1wbG95IHNlbnRpbWVudCBhbmFseXNpcyBhbmQgTERBIG1vZGVsIGFuYWx5c2lzIHRvIGV4cGxvcmUgY3VzdG9tZXIncyBuZWVkcyBhbmQgZXhwZWN0YXRpb24gYWJvdXQgRVYuCgoKCgoKIyMjICoqUGFydCAxOiBFeHBsb3JpbmcgdGhlIGRldmVsb3BtZW50IG9mIEVWIG1hcmtldCBhbmQgbWFqb3IgZmFjdG9ycyoqCgpJbiB0aGlzIHBhcnQsIHdlJ2xsIHZpc3VhbGl6ZSB0aGUgaGlzdG9yaWNhbCBkZXZlbG9wbWVudCBvZiBFVnMgaW4gTmV3IFlvcmsgU3RhdGUgYW5kIGFuYWx5emUgdGhlIG1ham9yIGRyaXZlcnMgZm9yIHRoZSByYXBpZCBncm93dGguIEZpcnN0LCBXZSdsbCBzdGFydCBieSBwcm92aWRpbmcgYSBoaXN0b3JpY2FsIG92ZXJ2aWV3IG9mIHRoZSBFViByZWdpc3RyYXRpb24uCgoKCiMjIyMgVGhlIHJhcGlkIGdyb3d0aCBvZiBFViByZWdpc3RyYXRpb24gaW4gTmV3IFlvcmsgU3RhdGUKCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnhsX2RhdGEgPC0gIkVWLVJlZ2lzdHJhdGlvbi1UYWJsZXMueGxzeCIKCkVWX3RpbWUgPC0gcmVhZF9leGNlbChwYXRoPXhsX2RhdGEsIHNoZWV0PTUpCgpFVl90aW1lIDwtIGhlYWQoRVZfdGltZSwgLTEpCgpFVl90aW1lIDwtIG11dGF0ZShFVl90aW1lLCBUaW1lPXBhc3RlKGBNb250aCBOYW1lYCwgc3RyaV9zdWIoRVZfdGltZSRZZWFyLCAzLDQpLCBzZXA9IiAnIikpCgoKcDEgPC0gRVZfdGltZSAlPiUKICBncm91cF9ieSgiWWVhciIpICU+JQogIGhjaGFydCguLCAiYXJlYSIsIGhjYWVzKHggPSBgVGltZWAsIHk9Y3Vtc3VtKGBUb3RhbCBFVnNgKSkpJT4lICAKICBoY190aXRsZSh0ZXh0ID0gIk9yaWdpbmFsIEVWIFJlZ2lzdHJhdGlvbiBpbiBOZXcgWW9yayBTdGF0ZSAoMjAxMS0yMDE5KSIpICU+JQogIGhjX3N1YnRpdGxlKHRleHQgPSAiU291cmNlOiBOZXcgWW9yayBTdGF0ZSBFbmVyZ3kgUmVzZWFyY2ggYW5kIERldmVsb3BtZW50IEF1dGhvcml0eSIpICU+JQogIGhjX3lBeGlzKHRpdGxlID0gbGlzdCh0ZXh0PSJDdW11bGF0aXZlIHN1bSBvZiBFViIpKQpwMQpgYGAKClRoZSBhYm92ZSBncmFwaCBzaG93cyB0aGUgY3VtdWxhdGl2ZSBudW1iZXIgb2YgRVYgcmVnaXN0cmF0aW9uIGluIE5ldyBZb3JrIFN0YXRlIHNpbmNlIDIwMTEuIEVWIHJlZ2lzdHJhdGlvbiBoYXMgZ3Jvd24gMTAwIHRpbWVzIGJldHdlZW4gRGVjZW1iZXIgMjAxMSB0byBEZWNlbWJlciAyMDE1LCBhbmQgaGFzIG1haW50YWluZWQgYSBzdGVhZHkgZ3Jvd3RoIHJhdGUgdXAgdGlsbCBub3cuIE5ldyBZb3JrZXJzIGhhdmUgZGVtb25zdHJhdGVkIHN0cm9uZyBpbnRlcmVzdCBmb3IgRVZzIG92ZXIgdGltZS4KCgoKCgoKCgoKIyMjIyAqKk1ham9yIGRyaXZlcnMgb2YgTmV3IFlvcmsgU3RhdGUgRVYgZ3Jvd3RoKiogCk5leHQsIHdlJ2xsIGV4cGxvcmUgc2V2ZXJhbCBrZXkgZHJpdmluZyBmYWN0b3JzIG9mIHJhcGlkIEVWIGdyb3d0aCBpbiBOZXcgWW9yayBTdGF0ZS4KCgoKCgoKIyMjIyAqKjFzdCBmYWN0b3I6IGdyb3dpbmcgcG9wdWxhdGlvbioqClRoZSBwb3B1bGF0aW9uIG9mIE5ldyBZb3JrIFN0YXRlIGhhcyBtYWludGFpbmVkIGEgZ3Jvd2luZyBwYWNlIGR1cmluZyB0aGUgZmlyc3QgaGFsZiBvZiAyMDEwcy4gSGVuY2UsIHRoaXMgY3JlYXRlcyBtb3JlIGRlbWFuZCBmb3IgYXV0byBpbmR1c3RyeSBpbmNsdWRpbmcgRVYuIAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBvcHVsYXRpb24gPC0gcmVhZF9leGNlbCgibnlfcG9wLnhsc3giKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpwMyA8LSBnZ3Bsb3QocG9wdWxhdGlvbiwgYWVzKHg9eWVhciwgeT1jdW1zdW0odG90YWxfcG9wdWxhdGlvbi8xMDAwMDAwKSwgdGV4dD1wYXN0ZSgiWWVhcjogIiwgeWVhciwKICI8YnI+Y3VtdWxhdGl2ZSBwb3B1bGF0aW9uIChNaWxsaW9ucyk6ICIsIGN1bXN1bSh0b3RhbF9wb3B1bGF0aW9uLzEwMDAwMDApKSkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLGFscGhhPS42LCB3aWR0aD0wLjgsIGZpbGw9ICIjMDg4MmM3IikrbGFicyh0aXRsZSA9ICJOZXcgWW9yayBTdGF0ZSBDdW11bGF0aXZlIFBvcHVsYXRpb24iLHN1YnRpdGxlID0gIlNvdXJjZTogVS5TLiBDZW5zdXMgQnVyZWF1IiwgeD0iWWVhciIseT0iQ3VtdWxhdGl2ZSBwb3B1bGF0aW9uIChpbiBtaWxsaW9ucykiKSsKICAgICAgICAgdGhlbWVfY2xhc3NpYygpKwogICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDIwMTAsIDIwMTEsMjAxMiwyMDEzLDIwMTQsMjAxNSwyMDE2LDIwMTcsMjAxOCwyMDE5KSwgbGFiZWxzID0gYygiMjAxMCIsICIyMDExIiwiMjAxMiIsICIyMDEzIiwiMjAxNCIsICIyMDE1IiwgIjIwMTYiLCAiMjAxNyIsICIyMDE4IiwgIjIwMTkiKSkKCmdncGxvdGx5KHAzLCB0b29sdGlwPSJ0ZXh0IikKYGBgCgoKCgoKCgojIyMjICoqMm5kIGZhY3RvcjogQ2FyYm9uIGVtaXNzaW9uIHJlZHVjdGlvbiBhbmQgcG9saWN5IHN1cHBvcnQqKgpEdXJpbmcgdGhlIHBhc3QgMyBkZWNhZGVzLCBnYXNvbGluZSBhbmQgZGllc2VsIHJlbWFpbiBhcyB0aGUgdG9wIDIgc291cmNlcyBvZiBncmVlZW5ob3VzZSBlbWlzc2lvbnMgdW5kZXIgdGhlIHRyYW5zcG9ydGF0aW9uIHNlY3RvciBpbiB0aGUgVS5TLi4gSGVuY2UsIE5ldyBZb3JrIFN0YXRlIGhhcyBpc3N1ZWQgYSBwYWNrYWdlIG9mIHBvbGljaWVzIHRvIGFjY2VsZXJhdGUgdGhlIGVsZWN0cmlmaWNhdGlvbiB0cmVuZCBpbiB0cmFuc3BvcnRhdGlvbi4gRm9yIGV4YW1wbGUsIE5ldyBZb3JrIFN0YXRlIGlzIG9uZSBvZiB0aGUgZmlyc3Qgc3RhdGVzIGluIHRoZSBVLlMuIHRvIHNpZ24gYSBaZXJvIEVtaXNzaW9uIFZlaGljbGUgTWVtb3JhbmR1bSBvZiBVbmRlcnN0YW5kaW5nIChaRVYgTU9VKSB0byBlbmFjdCBwb2xpY2llcyB0aGF0IHdpbGwgZW5zdXJlIHRoZSBkZXBsb3ltZW50IG9mIDMuMyBtaWxsaW9uCmxpZ2h0LWR1dHkgWkVWcyBieSAyMDI1LiBGdXJ0aGVybW9yZSwgdW5kZXIgTmV3IFlvcmsgU3RhdGUncyBDaGFyZ2UgTlkgaW5pdGlhdGl2ZSwgZWxlY3RyaWMgdmVoaWNsZSBidXllcnMgY2FuIHJlY2VpdmUgYSByZWJhdGUgb2YgdXAgdG8gMiwwMDAgZm9yIG5ldyBjYXIgcHVyY2hhc2VzIG9yIGxlYXNlcywgdG9nZXRoZXIgd2l0aCBhIEZlZGVyYWwgVGF4IENyZWRpdCBvZiB1cCB0byA3LDUwMC4gSW4gYWRkaXRpb24sIGF1dG9tb3RpdmUgbWFudWZhY2Z1cmVycyBhcmUgb2ZmZXJpbmcgbW9yZSBFViBtb2RlbHMgZm9yIGNvbnN1bWVycyB0byBjaG9vc2UsIHJhbmdpbmcgZnJvbSBjb3N0LWVmZmVjdGl2ZSB0byBsdXh1cnkgRVYuCgpUaGVyZWZvcmUsIHBvbGljeSBzdXBwb3J0IGFuZCB0aGUgaW5jcmVhc2luZyB2YXJpZXR5IG9mIEVWcyBtYWtlIGl0IGEgZ29vZCB0aW1pbmcgZm9yIGNvbnN1bWVycyB0byBwdXJjaGFzZSBFVi4KCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZW1pc3Npb24gPC0gcmVhZF9leGNlbCgibnlfZW1pc3Npb24ueGxzeCIpCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwNCA8LSBnZ3Bsb3QoZW1pc3Npb24sIGFlcyhmaWxsPXR5cGUsIHk9aW52ZW50b3J5LCB4PWFzLmZhY3Rvcih5ZWFyKSwgdGV4dD1wYXN0ZSgiWWVhcjogIiwgYXMuZmFjdG9yKHllYXIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+RW1pc3Npb25zIGludmVudG9yeTogIiwgaW52ZW50b3J5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+VHlwZTogIiwgdHlwZSkpKSsKICBnZW9tX2Jhcihwb3NpdGlvbj0iZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIsYWxwaGE9LjYsIHdpZHRoPTAuOCkgKwogICAgICAgICBsYWJzKHRpdGxlID0gIlRyYW5zcG9ydGF0aW9uIFNlY3RvciBHcmVlbmhvdXNlIEVtaXNzaW9ucyBJbnZlbnRvcnksIDE5OTDigJMyMDE2IixzdWJ0aXRsZSA9ICJTb3VyY2U6IE5ldyBZb3JrIFN0YXRlIEVuZXJneSBSZXNlYXJjaCBhbmQgRGV2ZWxvcG1lbnQgQXV0aG9yaXR5IiwgeD0iWWVhciIseT0iRW1pc3Npb25zIEludmVudG9yeSAoTU10Q08yZSkiKSsKICAgICAgICAgdGhlbWVfYncoKSsKICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90bHkocDQsIHRvb2x0aXA9InRleHQiKQpgYGAKCgoKCgoKIyMjIyAqKjNyZCBmYWN0b3I6IEluY3JlYXNpbmcgbnVtYmVyIGFuZCB2YXJpZXR5IG9mIEVWIG1vZGVscyBvZmZlcmVkKioKCkR1ZSB0byB0aGUgYm9vc3Qgb2YgZGVzaWduIGFuZCBiYXR0ZXJ5IHRlY2hub2xvZ3ksIG5vd2FkYXlzIGF1dG9tb3RpdmUgbWFudWZhY3R1cmVycyBhcmUgb2ZmZXJpbmcgdmFyaW91cyBraW5kcyBvZiBFViB0byB0aGUgY29uc3VtZXJzLiBJdCBpcyBlc3RpbWF0ZWQgdGhhdCB0aGUgbnVtYmVyIG9mIGJhdHRlcnkgZWxlY3RyaWMgKEJFVikgYW5kIHBsdWctaW4gaHlicmlkIChQSEVWKSBwYXNzZW5nZXIgdmVoaWNsZSBtb2RlbHMgYXZhaWxhYmxlIHRvIFUuUy4gY29uc3VtZXJzIHdpbGwgaW5jcmVhc2UgZnJvbSA2MCB0byA4MyBiZXR3ZWVuIDIwMjAgYW5kIDIwMjIuIE1lYW53aGlsZSwgbnVtZXJvdXMgbWFudWZhY3R1cmVycyBoYXZlIHB1YmxpY2x5IHNpZ25hbGVkIHRoZWlyIGludmVzdG1lbnQgcGxhbnMgYW5kIGNvbW1pdG1lbnRzIHRvIGEgZnV0dXJlIG9mIGVsZWN0cmljIHZlaGljbGUuIAoKSW4gYWRkaXRpb24sIEVWcyBoYXZlIGJlY29tZSBtb3JlIGFmZm9yZGFibGUgYmVjYXVzZSBvZiBkcmFtYXRpYyByZWR1Y3Rpb25zIGluIHRoZSBjb3N0IG9mIGJhdHRlcmllcy4gVGhlIGNvc3Qgb2YgYmF0dGVyeSBwYWNrcyBoYXMgZmFsbGVuIGZyb20gYXBwcm94aW1hdGVseSBcJDEsMDAwL2tpbG93YXR0LWhvdXIgKGtXaCkgaW4gMjAxMCB0byBhcHByb3hpbWF0ZWx5IFwkMTU2L2tXaCBpbiAyMDE5LiBUaGVzZSBmYWN0b3JzIGFsbCBjb250cmlidXRlIHRvIHRoZSBncm93dGggb2YgRVYgc2FsZXMuCgoKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKRVZfbWFrZSA8LSByZWFkX2V4Y2VsKHBhdGg9eGxfZGF0YSwgc2hlZXQ9MykKRVZfbWFrZSA8LSBoZWFkKEVWX21ha2UsIC0xKQpFVl9tYWtlIDwtIG11dGF0ZShFVl9tYWtlLCBOYW1lPXBhc3RlKE1ha2UsIE1vZGVsKSkKCnA1IDwtIEVWX21ha2UgJT4lCiAgaGNoYXJ0KCJ0cmVlbWFwIiwgaGNhZXMoeD0nTmFtZScsIHZhbHVlPSAnUmVnaXN0cmF0aW9ucycsIGNvbG9yPSAnUmVnaXN0cmF0aW9ucycpKSAlPiUKICAgICAgICAgICBoY190aXRsZSh0ZXh0ID0gIkVWIG1ha2UtbW9kZWxzIGluIE5ldyBZb3JrIFN0YXRlIGJ5IHBvcHVsYXJpdHkiKSAlPiUKICAgICAgICAgICBoY19zdWJ0aXRsZSh0ZXh0ID0gIlNvdXJjZTogTmV3IFlvcmsgU3RhdGUgRW5lcmd5IFJlc2VhcmNoIGFuZCBEZXZlbG9wbWVudCBBdXRob3JpdHkiKQpwNQpgYGAKClRoZSBhYm92ZSB0cmVlbWFwIHNob3dzIHRoZSBncmVhdCB2YXJpZXR5IG9mIEVWIG1vZGVscyBpbiB0aGUgY3VycmVudCBVLlMuIG1hcmtldC4gVGhlcmUgYXJlIDY2IEVWIG1vZGVscyAoUEhFViBhbmQgQkVWKSBieSAzMiBhdXRvbW90aXZlIG1hbnVmYWN0dXJlcnMgYXZhaWxhYmxlIHRvIFUuUy4gY29uc3VtZXJzLiBUZXNsYSBNb2RlbCAzIGFuZCBUb3lvdGEgUHJpdXMgUHJpbWUgZW5qb3kgdGhlIHByZWRvbWluYW50IHBvcHVsYXJpdHkgYW1vbmcgVS5TLiBjb25zdW1lciwgZm9sbG93ZWQgYnkgVGVzbGEgTW9kZWwgUywgQ2hldnJvbGV0IFZvbHQsIEZvcmQgRnVzaW9uIEVuZXJnaSwgYW5kIFRlc2xhIE1vZGVsIFguCgpJbiBhZGRpdGlvbiwgVS5TIGNvbnN1bWVycyBwcmVmZXIgZG9tZXN0aWMgY2FyIGJyYW5kcyAoVGVzbGEsIENoZXZyb2xldCwgRm9yZCkgdGhlIG1vc3QsIGZvbGxvd2VkIGJ5IEphcGFuZXNlIGJyYW5kIChUb3lvdGEsIEhvbmRhLCBhbmQgTmlzc2FuKS4gRXhjZXB0IGZvciB0aGUgdHdvIGx1eHVyeSBFViBtb2RlbHMgZnJvbSBUZXNsYSAoTW9kZWwgUyBhbmQgTW9kZWwgWCksIDggb3V0IG9mIHRoZSB0b3AgMTAgcG9wdWxhciBFVnMgYXJlIHVuZGVyIFwkNTAsMDAwIChNU1JQKS4gSXQgc3VnZ2VzdHMgdGhhdCBhZmZvcmRhYmlsaXR5IGFuZCBlbmVyZ3kgZWZmaWNpZW5jeSBhcmUgdGhlIGtleSBmYWN0b3JzIHdoZW4gaXQgY29tZXMgdG8gRVYgcHVyY2hhc2UgZm9yIE5ldyBZb3JrIGNvbnN1bWVycy4KCgoKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQptZXRyaWMgPSByZWFkX2V4Y2VsKCJldl9pbmZvLnhsc3giKQpgYGAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwNiA8LSBnZ3Bsb3QobWV0cmljLGFlcyh4ID0gcmFuZ2UsIHkgPSBNU1JQLzEwMDAsIGxhYmVsPXR5cGUpKSsKICAjZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGNvc3RfcGVyX21pbGUpLGFscGhhPS42KSsKICBnZW9tX3RleHQoYWVzKGNvbG9yPWZhY3RvcihicmFuZCkpLCBhbHBoYSA9IDAuNiwgdmp1c3Q9LTAuMiwgY2hlY2tfb3ZlcmxhcD1UUlVFLCBzaXplPTMuNSkrCiAgbGFicyh0aXRsZSA9ICJGZWF0dXJlcyBvZiBFViBieSBNYWtlLW1vZGVscyIsIHN1YnRpdGxlID0gIlNvdXJjZTogVmlzdWFsIENhcGl0YWxpc3QiLCB4PSJSYW5nZSBPbiBhIFNpbmdsZSBDaGFyZ2UobWlsZSkiLHk9Ik1hbnVmYWN0dXJlcidzIFN1Z2dlc3RlZCBSZXRhaWwgUHJpY2UoJGspIikrIGdlb21fbGFiZWwoKSt0aGVtZV9idygpKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdGx5KHA2KQpgYGAKCgpUaGUgYWJvdmUgZ3JhcGggb2ZmZXJzIG1vcmUgZGV0YWlsZWQgbWFrZS1tb2RlbHMgaW5mb3JtYXRpb24gb2YgdGhlIGN1cnJlbnQgRVYgbWFya2V0IGluIHRoZSBVLlMuLiBJbiB0ZXJtcyBvZiBhZmZvcmRhYmlsaXR5LCB0aGVyZSBhcmUgc2l4IEVWIG1vZGVscyBhdmFpbGFibGUgZm9yIHVuZGVyIFwkNTAsMDAwIChNU1JQKSB3aXRoIGEgZHJpdmluZyByYW5nZSBvZiB1cCB0byAyNTAgbWlsZXMuIFNwZWNpZmljYWxseSwgRVYgbW9kZWxzIGJ5IEphcGFuZXNlIGNhcm1ha2VycyAoTmlzc2FuLCBIeXVuZGFpKSBlbXBoYXNpcyB0aGUgbW9zdCBvbiBhZmZvcmRhYmlsaXR5LiBBbGwgb2YgdGhlIDUgRVYgbW9kZWxzIGJ5IEphcGFuZXNlIG1hbnVmYWN0dXJlcnMgYXJlIHVuZGVyIFwkNDAsMDAwIChNU1JQKS4gVGhlcmUgd2lsbCBiZSBldmVuIG1vcmUgbW9kZWxzIHdpdGggYSBuZXQgY29zdCBvZiB1bmRlciAkNTAsMDAwIHdoZW4gY3VycmVudCBmZWRlcmFsLCBzdGF0ZSwgYW5kIHJlYmF0ZXMgYXJlIGZhY3RvcmVkIGluLgoKCgoKCgoKCgoKCiMjIyAqKlBhcnQgMjogbWFwcGluZyB0aGUgbG9jYXRpb25zIG9mIEVWIGNoYXJnaW5nIHN0YXRpb25zIGluIE5ldyBZb3JrIFN0YXRlKioKCkluIHRoaXMgcGFydCwgd2UnbGwgbWFwIHRoZSBjdXJyZW50IGRpc3RyaWJ1dGlvbiBvZiBFViByZWdpc3RyYXRpb24gYW5kIGNoYXJnaW5nIHN0YXRpb25zIGluIE5ldyBZb3JrIFN0YXRlLCB0byBleGFtaW5lIHdoZXRoZXIgY2hhcmdpbmcgc3RhdGlvbnMgd291bGQgYWZmZWN0IEVWIHNhbGVzIGluIHRoZSBOWSBTdGF0ZS4gVGhlIGFzc3VtcHRpb24gaXMgdGhhdCB0aGUgbnVtYmVyIG9mIGNoYXJnaW5nIHN0YXRpb25zIGlzIHBvc2l0aXZlbHkgYXNzb2NpYXRlZCB3aXRoIEVWIHNhbGVzLiBCb3RoIEVWIGNoYXJnaW5nIHN0YXRpb24gYW5kIHJlZ2lzdHJhdGlvbiBkYXRhIGFyZSBkb3dubG9hZGVkIGZyb20gTmV3IFlvcmsgU3RhdGUgRW5lcmd5IFJlc2VhcmNoIGFuZCBEZXZlbG9wbWVudCBBdXRob3JpdHksIGFuZCB3ZXJlIHVwZGF0ZWQgaW4gMjAyMS4KCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY2hhcmdpbmcgPC0gcmVhZC5jc3YoIkVWX0NoYXJnaW5nX1N0YXRpb25zLmNzdiIpCgpjaGFyZ2luZzEgPC1jaGFyZ2luZyAlPiUKICBzZWxlY3QoQ2l0eSwgWklQLCBMYXRpdHVkZSwgTG9uZ2l0dWRlLEVWLkNvbm5lY3Rvci5UeXBlcywgQWNjZXNzLkRheXMuVGltZSkKICAKbSA8LSBsZWFmbGV0KGNoYXJnaW5nMSkgJT4lCiAgYWRkVGlsZXMoJ2h0dHA6Ly97c30uYmFzZW1hcHMuY2FydG9jZG4uY29tL2xpZ2h0X2FsbC97en0ve3h9L3t5fS5wbmcnKSU+JQogICAgIHNldFZpZXcoLTc1LjMxNjcsIDQzLjA5Mjg3LCB6b29tID0gNikKCgpjb250ZW50IDwtIHBhc3RlKCJDaXR5IG5hbWU6IixjaGFyZ2luZzEkQ2l0eSwiPGJyLz4iLAogICAgICAgICAgICAgICAgICJaaXBjb2RlOiIsIGNoYXJnaW5nMSRaSVAsIjxici8+IiwKICAgICAgICAgICAgICAgICAiRVYgQ29ubmVjdG9yIFR5cGVzOiIsY2hhcmdpbmcxJEVWLkNvbm5lY3Rvci5UeXBlcywiPGJyLz4iLAogICAgICAgICAgICAgICAgICJBY2Nlc3MgRGF5cyBUaW1lOiIsIGNoYXJnaW5nMSRBY2Nlc3MuRGF5cy5UaW1lLCAiPGJyLz4iKQoKCm0yIDwtIG0gJT4lIGFkZENpcmNsZXMocG9wdXAgPSBjb250ZW50KQoKbWNsdXN0IDwtIG0yICU+JSBhZGRDaXJjbGVNYXJrZXJzKHBvcHVwPWNvbnRlbnQsIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoKSkKbWNsdXN0CmBgYAoKCkZyb20gdGhlIGFib3ZlIG1hcCwgdGhlIGNvdmVyYWdlIHJhdGUgb2YgRVYgY2hhcmdpbmcgc3RhdGlvbnMgaW4gTmV3IFlvcmsgU3RhdGUgaXMgcHJldHR5IGhpZ2guIENoYXJnaW5nIHN0YXRpb25zIGFyZSBtb3N0bHkgZGlzdHJpYnV0ZWQgaW4gdGhlIHNvdXRoZWFzdCBOZXcgWW9yay4gVGhlIGNsdXN0ZXJzIG9mIEVWIGNoYXJnaW5nIHN0YXRpb25zIGFyZSBzaWduaWZpY2FudGx5IGNvcnJlbGF0ZWQgd2l0aCBwb3B1bGF0aW9uIGRlbnNpdHksIHdoZXJlIGJpZ2dlciBjaXRpZXMgaGF2ZSBtb3JlIGNoYXJnaW5nIHN0YXRpb25zLiBOZXcgWW9yayBDaXR5IGhhcyB0aGUgbW9zdCBjaGFyZ2luZyBzdGF0aW9ucywgZm9sbG93ZWQgYnkgb3RoZXIgbGFyZ2UgY2l0aWVzIHN1Y2ggYXMgQWxiYW55LCBCdWZmYWxvLCBSb2NoZXN0ZXIsIFlvbmtlcnMsIGFuZCBTeXJhY3VzZS4gTmV4dCwgbGV0J3MgZnVydGhlciBleHBsb3JlIHRoZSBkaXN0cmlidXRpb24gd2l0aGluIE5ZQy4KCgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cm55YmIgPC0gcmVhZE9HUigibnliYl8yMWEiLCBsYXllcj0ibnliYiIpCgoKY2hhcmdpbmcyIDwtIGNoYXJnaW5nMSAlPiUKICBmaWx0ZXIoQ2l0eSAlaW4lIGMoIk5ldyBZb3JrIiwgIkJyb254IiwgIlF1ZWVucyIsICJCcm9va2x5biIsICJTdGF0ZW4gSXNsYW5kIiwgIkxvbmcgSXNsYW5kIENpdHkiKSklPiUKICByZW5hbWUoQm9yb05hbWUgPSBDaXR5KQoKY2hhcmdpbmcyJEJvcm9OYW1lIDwtIGFzLmNoYXJhY3RlcihjaGFyZ2luZzIkQm9yb05hbWUpCmNoYXJnaW5nMiRCb3JvTmFtZVtjaGFyZ2luZzIkQm9yb05hbWUgPT0gIk5ldyBZb3JrIl0gPC0gIk1hbmhhdHRhbiIKY2hhcmdpbmcyJEJvcm9OYW1lW2NoYXJnaW5nMiRCb3JvTmFtZSA9PSAiTG9uZyBJc2xhbmQgQ2l0eSJdIDwtICJRdWVlbnMiCgoKY2hhcmdpbmczIDwtIGNoYXJnaW5nMiAlPiUKICBzZWxlY3QoQm9yb05hbWUpICU+JQogIGdyb3VwX2J5KEJvcm9OYW1lKSAlPiUKICBhZGRfY291bnQoQm9yb05hbWUpICU+JQogIGRpc3RpbmN0KCkKCm55YmIkbnVtYmVyX29mX2NoYXJnaW5nIDwtIGNoYXJnaW5nMyRuCgpwNyA8LSB0bV9zaGFwZShueWJiKSArIHRtX2ZpbGwoIm51bWJlcl9vZl9jaGFyZ2luZyIsIHRpdGxlPSJEZW5zaXR5IG9mIGNoYXJnaW5nIHN0YXRpb25zIGluIE5ZQyIsIHN0eWxlPSJwcmV0dHkiKSArCiAgdG1fYm9yZGVycyhhbHBoYT0wLjUpK3RtX3N0eWxlKCJ3aGl0ZSIpCgpwNwoKYGBgCgoKVGhlIGFib3ZlIG1hcCBpcyBhIGhlYXRtYXAgb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiBFViBjaGFyZ2luZyBzdGF0aW9ucyBpbiBOZXcgWW9yayBDaXR5LiBUaGVyZSBhcmUgMzI2IEVWIGNoYXJnaW5nIHN0YXRpb25zIGluIE1hbmhhdHRhbiwgZm9sbG93ZWQgYnkgNzUgaW4gQnJvb2tseW4sIDIxIGluIFF1ZWVucywgMTkgaW4gU3RhdGVuIElzbGFuZCwgYW5kIDE0IGluIEJyb254LiBOZXcgWW9ya2VycyBkb24ndCBuZWVkIHRvIHdvcnJ5IGFib3V0IGNoYXJnaW5nIHRoZWlyIEVWcyBpbiBNYW5oYXR0YW4gc2luY2UgdGhlIGJvcm91Z2ggaGFzIHRoZSBtb3N0IGNoYXJnaW5nIHN0YXRpb25zIGF2YWlsYWJsZSBpbiB0aGUgc3RhdGUuIAoKCgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cm55emlwID0gcmVhZF9leGNlbCgibnlfemlwY29kZS54bHN4IikKCm55emlwIDwtIG55emlwICU+JQogIHNlbGVjdChaaXAsIExhdGl0dWRlLCBMb25naXR1ZGUpCgpueXppcCRaaXAgPC0gYXMuY2hhcmFjdGVyKG55emlwJFppcCkKICAKCgpFVl9yZWdpc3RyYXRpb24gPC0gcmVhZF9leGNlbChwYXRoPXhsX2RhdGEsIHNoZWV0PTIpCkVWX3JlZ2lzdHJhdGlvbiA8LSBoZWFkKEVWX3JlZ2lzdHJhdGlvbiwgLTEpCkVWX3JlZ2lzdHJhdGlvbiA8LSBFVl9yZWdpc3RyYXRpb24gJT4lIHJlbmFtZShaaXAgPSBgWklQIENvZGVgKQoKdG90YWwgPC0gbGVmdF9qb2luKG55emlwLCBFVl9yZWdpc3RyYXRpb24sIGJ5PSgiWmlwIikpCnRvdGFsW2lzLm5hKHRvdGFsKV0gPC0gMAoKbW0gPC0gbGVhZmxldCh0b3RhbCkgJT4lCiAgYWRkVGlsZXMoJ2h0dHA6Ly97c30uYmFzZW1hcHMuY2FydG9jZG4uY29tL2xpZ2h0X2FsbC97en0ve3h9L3t5fS5wbmcnKSU+JQogICAgIHNldFZpZXcoLTc1LjMxNjcsIDQzLjA5Mjg3LCB6b29tID0gNikKCmNvbnRlbnQyIDwtIHBhc3RlKCJaaXBjb2RlOiIsIHRvdGFsJFppcCwiPGJyLz4iLAogICAgICAgICAgICAgICAgICJOdW1iZXIgb2YgUEhFVi9FUkVWOiIsdG90YWwkYFBIRVYvRVJFVmAsIjxici8+IiwKICAgICAgICAgICAgICAgICAiTnVtYmVyIG9mIEJFVjoiLCB0b3RhbCRCRVYsICI8YnIvPiIsCiAgICAgICAgICAgICAgICAgIlRvdGFsIEVWczoiLCB0b3RhbCRgVG90YWwgRVZzYCwgIjxici8+IikKCm0zIDwtIG1tICU+JSBhZGRDaXJjbGVzKHBvcHVwID0gY29udGVudDIpCgptY2x1c3QyIDwtIG0zICU+JSBhZGRDaXJjbGVNYXJrZXJzKHBvcHVwPWNvbnRlbnQyLCBjbHVzdGVyT3B0aW9ucyA9IG1hcmtlckNsdXN0ZXJPcHRpb25zKCkpCgptY2x1c3QyCmBgYAoKClRoZSBhYm92ZSBtYXAgZGlzcGxheXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBFViByZWdpc3RyYXRpb24gaW4gTmV3IFlvcmsgU3RhdGUgYnkgemlwY29kZS4gVGhlIGRhdGEgaXMgZG93bmxvYWRlZCBmcm9tIE5ldyBZb3JrIFN0YXRlIEVuZXJneSBSZXNlYXJjaCBhbmQgRGV2ZWxvcG1lbnQgQXV0aG9yaXR5IGFuZCBpcyB1cGRhdGVkIGluIDIwMjEuIEVWIHJlZ2lzdHJhdGlvbiBzZWVtcyB0byBiZSByb3VnaGx5IGV2ZW4gZGlzdHJpYnV0ZWQgdGhyb3VnaG91dCBOWSBzdGF0ZSBhdCBmaXJzdCBnbGFuY2UuIEVWcyBhcmUgbW9zdGx5IGRpc3RyaWJ1dGVkIGluIHRoZSBTb3V0aGVhc3QgTmV3IFlvcmssIHdoaWNoIGlzIHRoZSBzYW1lIHBhdHRlcm4gYXMgc2hvd24gaW4gdGhlIG1hcCBvZiBjaGFyZ2luZyBzdGF0aW9ucy4gCgpDb21wYXJpbmcgdGhlIHR3byBtYXBzLCBFVi1jaGFyZ2luZyBzdGF0aW9uIHJhdGlvIGlzIHByZXR0eSBoaWdoIGluIE5vcnRoZWFzdCBhbmQgY2VudHJhbCBOWSwgd2hlcmUgbW9yZSBFVnMgYXJlIHJlZ2lzdHJhdGVkIGJ1dCB3aXRoIGZld2VyIGNoYXJnaW5nIHN0YXRpb25zLiBCeSBjb250cmFzdCwgRVYtY2hhcmdpbmcgc3RhdGlvbiByYXRpbyBpcyBsb3dlc3QgaW4gTmV3IFlvcmsgQ2l0eS4KCgoKCgoKCgoKIyMjICoqUGFydCAzOiBMREEgbW9kZWwgYW5hbHlzaXMgb2YgRVYtcmVsYXRlZCB0d2VldHMqKgoKSW4gdGhpcyBwYXJ0LCB3ZSdsbCBwZXJmb3JtIE5MUCBhbmFseXNpcyByZWxhdGluZyB0byBFVnMsIGluY2x1ZGluZyBMREEgYW5hbHlzaXMsIFdvcmQgY2xvdWQgYW5hbHlzaXMgYW5kIHNlbnRpbWVudCBhbmFseXNpcy4gT3VyIGRhdGEgc2NyYXBlZCAxMSw3MDYgdHdlZXRzIGZyb20gVHdpdHRlciBiZXR3ZWVuIDIwMjEtMDQtMDYgdG8gMjAyMS0wNC0xNC4gVGhlIGRhdGF0YWJsZSBiZWxvdyBpcyBhbiBpbnRlcmFjdGl2ZSB0YWJsZSBkaXNwbGF5aW5nIG91ciBvcmlnaW5hbCB0ZXh0cy4gWW91IGNhbiBzZWFyY2ggZm9yIHNwZWNpZmljIHRleHRzIGJhc2VkIG9uIGRhdGUgb3Iga2V5d29yZHMuCgoKCgoKCgojIyMjICoqMy4xIEludGVyYWN0aXZlIHRhYmxlIGZvciBFVi1yZWxhdGVkIHR3ZWV0cyoqCgoKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpkYXRhID0gcmVhZC5jc3YoImV2dHdlZXRzLmNzdiIpCmRhdGEgPSBkYXRhICU+JQogIHNlbGVjdCgiRGF0ZSIsIlR3ZWV0cyIpCmxpYnJhcnkoRFQpCmxpYnJhcnkoZGF0YS50YWJsZSkKZHQgPC0gZGF0YXRhYmxlKGRhdGEsIGZpbHRlciA9IGxpc3QocG9zaXRpb249J3RvcCcpKQpkdApgYGAKCgoKCgoKCiMjIyMgKiozLjIgVmlzdWFsaXphdGlvbiBvZiBMREEgbW9kZWwgcmVzdWx0cyoqCgoKQmVsb3cgc2hvd3MgdGhlIHNjcmVlbnNob3RzIG9mIHRoZSB0aHJlZSBMREEgdG9waWNzLiAKYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSgiTERBdmlzIikKbGlicmFyeShOTFApCmxpYnJhcnkodG0pCmxpYnJhcnkoInNlcnZyIikKbGlicmFyeShzaGlueSkKbGlicmFyeSgibGRhIikKCmRhdGExIDwtIHJlYWQuY3N2KCJldnR3LmNzdiIpCnN0b3Bfd29yZHMgPC0gc3RvcHdvcmRzKCJTTUFSVCIpCnR3ZWV0IDwtIGRhdGExJHVzZXRleHQKdHdlZXQgPC0gZ3N1YigiXltbOnNwYWNlOl1dKyIsICIiLCB0d2VldCkgIyByZW1vdmUgd2hpdGVzcGFjZSBhdCBiZWdpbm5pbmcgb2YgZG9jdW1lbnRzCnR3ZWV0IDwtIGdzdWIoIltbOnNwYWNlOl1dKyQiLCAiIiwgdHdlZXQpICMgcmVtb3ZlIHdoaXRlc3BhY2UgYXQgZW5kIG9mIGRvY3VtZW50cwoKIyB0b2tlbml6ZSBvbiBzcGFjZSBhbmQgb3V0cHV0IGFzIGEgbGlzdDoKZG9jLmxpc3QgPC0gc3Ryc3BsaXQodHdlZXQsICJbWzpzcGFjZTpdXSsiKQoKIyBjb21wdXRlIHRoZSB0YWJsZSBvZiB0ZXJtczoKdGVybS50YWJsZSA8LSB0YWJsZSh1bmxpc3QoZG9jLmxpc3QpKQp0ZXJtLnRhYmxlIDwtIHNvcnQodGVybS50YWJsZSwgZGVjcmVhc2luZyA9IFRSVUUpCgojIHJlbW92ZSB0ZXJtcyB0aGF0IGFyZSBzdG9wIHdvcmRzIG9yIG9jY3VyIGZld2VyIHRoYW4gMTAgdGltZXM6CmRlbCA8LSBuYW1lcyh0ZXJtLnRhYmxlKSAlaW4lIHN0b3Bfd29yZHMgfCB0ZXJtLnRhYmxlIDwgMTAKdGVybS50YWJsZSA8LSB0ZXJtLnRhYmxlWyFkZWxdCnZvY2FiIDwtIG5hbWVzKHRlcm0udGFibGUpCgojIHByZXBhcmUgZG9jdW1lbnRzIGZvciBsZGE6CmdldC50ZXJtcyA8LSBmdW5jdGlvbih4KSB7CiAgaW5kZXggPC0gbWF0Y2goeCwgdm9jYWIpCiAgaW5kZXggPC0gaW5kZXhbIWlzLm5hKGluZGV4KV0KICByYmluZChhcy5pbnRlZ2VyKGluZGV4IC0gMSksIGFzLmludGVnZXIocmVwKDEsIGxlbmd0aChpbmRleCkpKSkKfQpkb2N1bWVudHMgPC0gbGFwcGx5KGRvYy5saXN0LCBnZXQudGVybXMpCgojIENvbXB1dGUgc29tZSBzdGF0aXN0aWNzIHJlbGF0ZWQgdG8gdGhlIGRhdGEgc2V0OgpEIDwtIGxlbmd0aChkb2N1bWVudHMpICAjIG51bWJlciBvZiBkb2N1bWVudHMgKDIsMDAwKQpXIDwtIGxlbmd0aCh2b2NhYikgICMgbnVtYmVyIG9mIHRlcm1zIGluIHRoZSB2b2NhYiAoMTQsNTY4KQpkb2MubGVuZ3RoIDwtIHNhcHBseShkb2N1bWVudHMsIGZ1bmN0aW9uKHgpIHN1bSh4WzIsIF0pKSAgIyBudW1iZXIgb2YgdG9rZW5zIHBlciBkb2N1bWVudCAKTiA8LSBzdW0oZG9jLmxlbmd0aCkgICMgdG90YWwgbnVtYmVyIG9mIHRva2VucyBpbiB0aGUgZGF0YSAKdGVybS5mcmVxdWVuY3kgPC0gYXMuaW50ZWdlcih0ZXJtLnRhYmxlKSAgIyBmcmVxdWVuY2llcyBvZiB0ZXJtcyBpbiB0aGUgY29ycHVzIAoKIyBGaXQgdGhlIG1vZGVsOgpsaWJyYXJ5KGxkYSkKc2V0LnNlZWQoMSkKCmZpdCA8LSBsZGEuY29sbGFwc2VkLmdpYmJzLnNhbXBsZXIoZG9jdW1lbnRzID0gZG9jdW1lbnRzLCBLID0gMywgdm9jYWIgPSB2b2NhYiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtLml0ZXJhdGlvbnMgPSAyNTAsIGFscGhhID0gMC41LCBldGE9MC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRpYWwgPSBOVUxMLCBidXJuaW4gPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXB1dGUubG9nLmxpa2VsaWhvb2QgPSBUUlVFKQoKI0xEQXZpcwp0aGV0YSA8LSB0KGFwcGx5KGZpdCRkb2N1bWVudF9zdW1zICsgMC4xLCAyLCBmdW5jdGlvbih4KSB4L3N1bSh4KSkpCnBoaSA8LSB0KGFwcGx5KHQoZml0JHRvcGljcykgKyAwLjEsIDIsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKSkKCnR3ZWV0dmlzIDwtIGxpc3QocGhpID0gcGhpLAogICAgICAgICAgICAgICAgIHRoZXRhID0gdGhldGEsCiAgICAgICAgICAgICAgICAgZG9jLmxlbmd0aCA9IGRvYy5sZW5ndGgsCiAgICAgICAgICAgICAgICAgdm9jYWIgPSB2b2NhYiwKICAgICAgICAgICAgICAgICB0ZXJtLmZyZXF1ZW5jeSA9IHRlcm0uZnJlcXVlbmN5KQoKCiMgY3JlYXRlIHZpc3VhbGl6YXRpb24KanNvbiA8LSBjcmVhdGVKU09OKHBoaSA9IHR3ZWV0dmlzJHBoaSwgCiAgICAgICAgICAgICAgICAgICB0aGV0YSA9IHR3ZWV0dmlzJHRoZXRhLCAKICAgICAgICAgICAgICAgICAgIGRvYy5sZW5ndGggPSB0d2VldHZpcyRkb2MubGVuZ3RoLCAKICAgICAgICAgICAgICAgICAgIHZvY2FiID0gdHdlZXR2aXMkdm9jYWIsIAogICAgICAgICAgICAgICAgICAgdGVybS5mcmVxdWVuY3kgPSB0d2VldHZpcyR0ZXJtLmZyZXF1ZW5jeSkKCnNlclZpcyhqc29uLCBvdXQuZGlyID0gdGVtcGZpbGUoKSwgb3Blbi5icm93c2VyID0gaW50ZXJhY3RpdmUoKSkKYGBgCgohW1Zpc3VhbGl6YXRpb24gb2YgVG9waWMgMV0odG9waWMxLnBuZykKCgoKIVtWaXN1YWxpemF0aW9uIG9mIFRvcGljIDJdKHRvcGljMi5wbmcpCgoKCiFbVmlzdWFsaXphdGlvbiBvZiBUb3BpYyAzXSh0b3BpYzMucG5nKQoKCgoKCgoKCgoKCgoKCioqRnJvbSB0aGUgTERBIHZpc3VhbGl6YXRpb24gYWJvdmUsIHdlIGNhdGVnb3JpemUgb3VyIGRvY3VtZW50cyBpbnRvIDMgdG9waWNzOiBJbmZyYXN0cnVjdHVyZSBNYXR1cml0eSwgRXhwZXJpZW5jZSBTaGFyaW5nLCBhbmQgVGVjaG5vbG9naWNhbCBFbGVtZW50cy4qKiAKCjEpICoqVG9waWMgMSoqOiBJbmZyYXN0cnVjdHVyZSBNYXR1cml0eSBkaXNwbGF5cyBjb21tb24gd29yZHMgc3VjaCBhcyAiY2hhcmdpbmciIGFuZCAic3RhdGlvbiIuIEJ1aWxkaW5nIEVWLXJlbGF0ZWQgbmZyYXN0cnV0dXJlIGlzIGltcG9ydGFudCB0byB0aGUgZGV2ZWxvcG1lbnQgb2YgZWxlY3RyaWMgY2Fycy4gVGhlcmUncyBubyBkb3VidCB0aGF0IGN1c3RvbWVycyBwYXkgYXR0ZW50aW9uIHRvIHN1Y2ggYXNwZWN0LiAgIAoKMikgKipUb3BpYyAyKio6IEV4cGVyaWVuY2UgU2hhcmluZyBkaXNwbGF5cyBjb21tb24gd29yZHMgc3VjaCBhcyAicmFuZ2UiIGFuZCAicHJpY2UiLiBDdXN0b21lcnMgb2Z0ZW4gc2hhcmUgdGhlaXIgcGVyc29uYWwgZXhwZXJpZW5jZSB3aXRoIEVWcyBvbiBUd2l0dGVyLiBGb3IgZXhhbXBsZSwgdGhleSB2YWx1ZSB0aGUgcHJpY2UgYW5kIGRyaXZpbmcgcmFuZ2Ugb2YgRVZzLiAgICAgCgozKSAqKlRvcGljIDMqKjogVGVjaG5vbG9naWNhbCBFbGVtZW50cyBjb250YWlucyB3b3JkcyBzdWNoIGFzICJiYXR0ZXJ5IiwgImdhcyIgYW5kICJwbGFuIi4gUGVvcGxlIGNhcmUgYWJvdXQgdGhlIGJhdHRlcnkgb2YgRVZzLCBlc3BlY2lhbGx5IGluIHNvbWUgbGVhZGluZyBicmFuZHMgc3VjaCBhcyBUZXNsYSBhbmQgUG9sZXN0YXIuIFRoZXkgYWxzbyBjb21wYXJlIHRoZSBlbmR1cmFuY2UgcG93ZXIgYmV0d2VlbiBlbGVjdHJpY3R5IGFuZCBnYXMuIAogICAgCk9uIHRoZSBsZWZ0IGhhbmQgc2lkZSBvZiB0aGlzIGdyYXBoIGFyZSB0aHJlZSBkaWZmZXJlbnQtc2l6ZWQgYnViYmxlLiBUaGUgbGFyZ2VyIHRoZSBidWJibGUgaXMsIHRoZSBtb3JlIHByZXZhbGVudCB0aGUgdG9waWMgaXMuIFRoZSBkZXRhaWxlZCBwcmV2YWxlbmNlIHJhbmtpbmcgaXM6IEluZnJhc3RydWN0dXJlIE1hdHVyaXR5ID4gRXhwZXJpZW5jZSBTaGFyaW5nID4gVGVjaG5vbG9naWNhbCBFbGVtZW50cy4KCklmIHlvdSB3b3VsZCBsaWtlIHRvIHBsYXkgYXJvdW5kIHdpdGggdGhlIExEQSBtZXRyaWNzIGFuZCB0b3Agd29yZHMsIFdlJ3ZlIGFsc28gaW5jbHVkZWQgYW5vdGhlciBodG1sIGZpbGUgdGhhdCB3YXMgY29uZHVjdGVkIGluIFB5dGhvbiBpbiB0aGUgR2l0aHViIHJlcG9zaXRvcnkuIAoKCgpgYGB7ciBlY2hvPUZBTFNFfQpkZiA8LSByZWFkLmNzdigiZXZ0d2VldHMuY3N2IikKYGBgCgoKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CiMjIyMgUHJlcHJvc2Vzc2luZwplbGVjdHJpYyA8LSBkZiAlPiUKICBzZWxlY3QoRGF0ZSwgY2xlYW5fdGV4dCkgCgpjb2xuYW1lcyhlbGVjdHJpYylbMV0gPC0gImRvY19pZCIKY29sbmFtZXMoZWxlY3RyaWMpWzJdIDwtICJ0ZXh0IgplbGVjdHJpY19mb3JfY29ycHVzIDwtIGVsZWN0cmljICU+JQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoZG9jX2lkLCB0ZXh0KQpkZl9zb3VyY2UgPC0gRGF0YWZyYW1lU291cmNlKGVsZWN0cmljX2Zvcl9jb3JwdXMpCgpgYGAKCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQojIyMjIENyZWF0aW5nIGNvcnB1cyAKbGlicmFyeSh0bSkKZGZfY29ycHVzX2VsZWN0cmljIDwtIFZDb3JwdXMoZGZfc291cmNlKQpkZl9jb3JwdXNfZWxlY3RyaWMKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQojIyMjIFRleHQgQ2xlYW5pbmc6IHJlbW92ZSBjZXJ0YWluIHdvcmRzCmNsZWFuX2NvcnB1cyA8LSBmdW5jdGlvbihjb3JwdXMpewogIGNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLHJlbW92ZVdvcmRzLCBjKCJlbGVjdHJpYyIsICJjYXIiLCAiaHR0cCIsInZlaGljbGUiKSkKICBjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgY29udGVudF90cmFuc2Zvcm1lcih0b2xvd2VyKSkKICBjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIGMoc3RvcHdvcmRzKCJlbiIpKSkKICBjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlTnVtYmVycykKICBjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgc3RyaXBXaGl0ZXNwYWNlKQogIHJldHVybihjb3JwdXMpCn0KCmVsZWN0cmljX2NsZWFuIDwtIGNsZWFuX2NvcnB1cyhkZl9jb3JwdXNfZWxlY3RyaWMpCmBgYAoKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CiMjIyMgU3RlbW1pbmcgCmxpYnJhcnkoU25vd2JhbGxDKQoKZWxlY3RyaWNfc3RlbW1lZCA8LSB0bV9tYXAoZGZfY29ycHVzX2VsZWN0cmljLCBzdGVtRG9jdW1lbnQpCgojIFNob3cgb25lIGV4YW1wbGUKZWxlY3RyaWNfc3RlbW1lZFtbMTVdXSRjb250ZW50CgpgYGAKCgoKKioqCgoKCgoKCgojIyMjICoqMy4zIFR3aXR0ZXIgc2VudGltZW50IGFuYWx5c2lzKioKClRoZSBDT1ZJRC0xOSBjcmlzaXMgaGFzIHNoaWZ0ZWQgdGhlIEVWIGxhbmRzY2FwZSBpbiBtdWx0aXBsZSBhcmVhcy4gQ291cGxlZCB3aXRoIHJhcGlkIGNvbGxhcHNlIG9mIHRyYWRlIGFuZCBlbXBsb3ltZW50LCBjb25zdW1lciBwdXJjaGFzaW5nIHBvd2VyIGhhcyBkZWNyZWFzZWQ7IHRoaXMgbG93ZXJpbmcgY29uc3VtZXIgZGVtYW5kIGluIHR1cm4gY29udHJpYnV0ZWQgdG8gYSBzaWduaWZpY2FudCBwbHVuZ2UgaW4gb2lsIHByaWNlcyBhbmQgY2hlYXBlciBnYXNvbGluZSBwcmljZXMsIHdoaWNoIGluIGhpbmRzaWdodCB3b3VsZCBib29zdCB0cmFkaXRpb25hbCBhdXRvbW9iaWxlIHNhbGVzLiBUaGUgcGFuZGVtaWMgYWxzbyBoYXMgc2xvd2VkIEVWIG9mZmVyaW5ncyB3aXRoIG51bWVyb3VzIHBsYW50cyBhbmQgYXV0by1hc3NlbWJseSBsaW5lcyBzaHV0dGluZyBkb3duIGluIDIwMjAuIERlc3BpdGUgdGhlc2UgbmVnYXRpdmUgZXh0ZXJuYWxpdGllcywgZWxlY3RyaWMgbW9iaWxpdHkgaGFzIHJlbWFpbmVkIHJlc2lsaWVudCAKd2l0aCByZWxhdGl2ZWx5IHN0YWJsZSBFViBzYWxlcy4gRnJvbSBhIHBvbGljeSBzdGFuZHBvaW50LCB0aGUgQ09WSUQtMTkgY3Jpc2lzIG1heSBoYXZlIHByb21wdGVkIHBvc2l0aXZlIGNoYW5nZXMgaW4gZW1pc3Npb24gcmVndWxhdGlvbiBhbmQgaW5jZW50aXZlcywgY3JlYXRpbmcgcG9zaXRpdmUgc2lnbmFscyBmb3IgcG90ZW50aWFsIEVWIGJ1eWVycy4gRm9yIGluc3RhbmNlLCBzZXZlcmFsIGdvdmVybm1lbnRzIGhhdmUgaW1wcm92ZWQgcHVyY2hhc2UgaW5jZW50aXZlcyAKc3VjaCBhcyB0YXggZXhlbXB0aW9ucyBhbmQgcHVyY2hhc2Ugc3Vic2lkaWVzLCBhcyB3ZWxsIGFzIGV4cGFuZGluZyBsb3ctZW1pc3Npb24gem9uZXMgd2l0aCBpbmNyZWFzZWQgcHVibGljIGNoYXJnaW5nIGluZnJhc3RydWN0dXJlLiAKCldpdGggYSB0aG9yb3VnaCB1bmRlcnN0YW5kaW5nIG9mIHRoZSBjaGFuZ2luZyBFViBpbmR1c3RyeSBsYW5kc2NhcGUsIHdlIGFpbSB0byB1bmRlcnN0YW5kIGhvdyBjdXN0b21lcnMnIHBlcmNlcHRpb25zIHRvd2FyZHMgRVZzIGhhdmUgZXZvbHZlZCBpbiB0aGUgbWlkc3Qgb2YgdGhlIHBhbmRlbWljLiBBcyBhIHJlc3VsdCwgb3VyIHRlYW0gZGVjaWRlZCB0byByZXRyaWV2ZSBFViByZWxhdGVkIHR3aXR0ZXIgcG9zdHMgZnJvbSBBcHJpbCA2dGggLSBBcHJpbCAxNHRoLCAKMjAyMSB0byBhbnN3ZXIgdGhlIGZvbGxvd2luZyByZXNlYXJjaCBxdWVzdGlvbnM6IAoKCiogVW5kZXJzdGFuZCB3aGF0IGFyZSBwZW9wbGUgdGFsa2luZyBhYm91dDogaWRlbnRpZnkgY29uc3VtZXJz4oCZIGNvbmNlcm5zIGFuZCBuZWVkcyAKKiBNZWFzdXJlIGN1c3RvbWVyc+KAmSBwZXJjZXB0aW9ucyB0b3dhcmRzIEVWIGluIHRoZSBtaWRzdCBvZiB0aGUgcGFuZGVtaWMgY3Jpc2lzOiBhc3Nlc3Mgd2hldGhlciB0aGV5IGhvbGQgcG9zaXRpdmUgb3IgbmVnYXRpdmUgCnNlbnRpbWVudAoqIEdhaW4gRm9yd2FyZC1sb29raW5nIHBlcnNwZWN0aXZlczogZ2F1Z2UgY3VzdG9tZXIgcGVyc3BlY3RpdmVzIHdpdGggcmVnYXJkcyB0byB0aGUgZnV0dXJlIG9mIGVsZWN0cmljIG1vYmlsaXR5CgoqKioKCgoKCgojIyMjICoqMy4zLjEgSWRlbnRpZnkgZnJlcXVlbnRseSBtZW50aW9uZWQgdGVybXMqKiAKCk91ciB0ZWFtIGh5cG90aGVzaXplZCB0aGF0IHNjcmFwcGluZyB0d2l0dGVyIHBvc3RzIGNvdWxkIHNoZWQgbGlnaHQgb24gY3VycmVudCBFViBlYXJseSBhZG9wdGVyc+KAmSBwYWluIHBvaW50cyB3aGlsZSByZWZsZWN0aW5nIHBvdGVudGlhbCAKRVYgYnV5ZXJzJyBrZXkgZGVjaXNpb24tbWFraW5nIGNyaXRlcmlhIHVwb24gcHVyY2hhc2luZyBhbiBlbGVjdHJpY2FsIHZlaGljbGUuIEFzIGEgcmVzdWx0LCB3ZSBmaXJzdCBjcmVhdGVkIGEgd29yZCBjbG91ZCB3aXRoIHRoZSBiaWdnZXIgc2l6ZWQgd29yZHMgaW5kaWNhdGluZyBhIGhpZ2hlciBmcmVxdWVuY3kuIEZyb20gdGhlIHdvcmQgY2xvdWQsIHdlIGNhbiBpZGVudGlmeSBjb21tb25seSBtZW50aW9uZWQgd29yZHMgbGlrZSDigJxuZXfigJ0sIOKAnHRlc2xh4oCdLCDigJxiYXR0ZXJ54oCdLCBhbmQg4oCcY2hhcmdpbmcu4oCdIE90aGVyIG1lYW5pbmdmdWwgZnJlcXVlbnRseSB1c2VkIHRlcm1zIGluY2x1ZGUg4oCcY2FyYm9u4oCdLCDigJxhbXDigJ0sIOKAnGNvc3TigJ0gYW5kICJ0YXguIgoKCmBgYHtyIGVjaG89VFJVRX0KZWxlY3RyaWNfdGRtIDwtIFRlcm1Eb2N1bWVudE1hdHJpeChlbGVjdHJpY19jbGVhbikKCmVsZWN0cmljX20gPC0gYXMubWF0cml4KGVsZWN0cmljX3RkbSkKCndvcmRzIDwtIHNvcnQocm93U3VtcyhlbGVjdHJpY19tKSxkZWNyZWFzaW5nPVRSVUUpIAplbGVjdHJpY19kZiA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh3b3JkcyksZnJlcT13b3JkcykKYGBgCgoKYGBge3IgZWNobz1UUlVFfQoKbGlicmFyeSh3b3JkY2xvdWQpCgpzZXQuc2VlZCgxMjM0KSAjIGZvciByZXByb2R1Y2liaWxpdHkgCgojIENyZWF0ZSBwdXJwbGVfb3JhbmdlCnB1cnBsZV9vcmFuZ2UgPC0gYnJld2VyLnBhbCgxMCwgIlB1T3IiKQojIERyb3AgMiBmYWludGVzdCBjb2xvcnMKcHVycGxlX29yYW5nZSA8LSBwdXJwbGVfb3JhbmdlWy0oMToyKV0KCiMgQ3JlYXRlIGEgd29yZGNsb3VkIHdpdGggcHVycGxlX29yYW5nZSBwYWxldHRlCnAxIDwtIHdvcmRjbG91ZCh3b3JkcyA9IGVsZWN0cmljX2RmJHdvcmQsIGZyZXEgPSBlbGVjdHJpY19kZiRmcmVxLAogICAgICBtYXgud29yZHMgPSAxMDAsIGNvbG9ycyA9IHB1cnBsZV9vcmFuZ2UpIAoKYGBgCgoKCgoKIyMjIyAqKjMuMy4yIEN1c3RvbWVyIG5lZWQgYW5hbHlzaXM6IGhpZ2hsaWdodGluZyB0aHJlZSBtYWpvciBFViBjb25zdW1lciBuZWVkcyoqCgoKCioqQ2hhcmdpbmcgSW5mcmFzdHJ1Y3R1cmUqKjogT25lIG9mIHRoZSBiaWdnZXN0IGNoYWxsZW5nZXMgaW4gdGhlIGVsZWN0cmljIG1vYmlsaXR5IGJ1c2luZXNzIGlzIHdoZXRoZXIgdGhlIGNoYXJnaW5nIGluZnJhc3RydWN0dXJlIGNhbiBrZWVwIHVwIHdpdGggZ3Jvd2luZyBFViBkZW1hbmQuIFdpdGhvdXQgc3VmZmljaWVudCBhY2Nlc3MgdG8gY2hhcmdpbmcgc3RhdGlvbnMsIGN1c3RvbWVycyBtdXN0IGRyaXZlIGV4dHJhIG1pbGVzIHRvIGZpbmQgdGhlIG5lYXJlc3Qgc3RhdGlvbix0aGVyZWJ5IHVuZGVybWluaW5nIHRoZWlyIHB1cmNoYXNlIGludGVudGlvbnMuIElkZWFsbHksIGNoYXJnaW5nIHN0YXRpb25zIHNob3VsZCBiZSB3aWRlbHkgYXZhaWxhYmxlIGluIHZhc3QgcGFya2luZyBsb3RzIHdoZXJlIApHUFMgY291bGQgZWFzaWx5IGxvY2F0ZS4KCgoKKipCYXR0ZXJ5IFN0b3JhZ2UgYW5kIExvbmdldml0eSoqOiBBc2lkZSBmcm9tIHRoZSB1cC1mcm9udCBFViBvd25lcnNoaXAgY29zdHMsIGJhdHRlcnktY29zdCBhbmQgZWZmaWNpZW5jeSBpbXByb3ZlbWVudHMgYXJlIG9mIGludGVyZXN0IHRvIG1hbnkgcG90ZW50aWFsIEVWIGJ1eWVycy4gTW9zdCByZWNlbnRseSwgYSBuZXcgdG9waWMgb2YgYmF0dGVyeSBsZWFzaW5nIGlzIGVtZXJnaW5nOiAiYmF0dGVyaWVzIGNvdWxkIGJlIGxlYXNlZCBzZXBhcmF0ZWx5IGZyb20gdGhlIEVWIGFuZCBiZSByZXNvbGQgdG8gdGhlIHN0YXRpb25hcnkgc3RvcmFnZSBtYXJrZXQgZm9yIHNlY29uZGFyeSB1c2UuIiBUaGlzIG1heSBhdHRyYWN0IG1vcmUgcG90ZW50aWFsIEVWIGJ1eWVycyB3aG8gd2VyZSBpbnRpYWxseSB3b3JyaWVkIGFib3V0IHRoZSBkZWdyYWRpbmcgY2FwYWNpdHkgb2YgRVYgYmF0dGVyaWVzIHRoaXMgZGF5LiAgIAoKCgoqKlRlc2xhJ3MgUHJlbWl1bSBQb3NpdGlvbmluZyoqOiBBbG9uZyB3aXRoIHRoZSByaXNlIG9mIHJlbmV3YWJsZSBlbmVyZ3ksIFRlc2xhIGhhcyBwaW9uZWVyZWQgdGhlIEVWIGluZHVzdHJ5IHdpdGggbHV4dXJ5IGVsZWN0cmljIGNhcnMgaW4gdGhlIHBhc3QgZGVjYWRlLiBJbiBmYWN0LCBvbmUgb2YgdGhlIGtleSBidXNpbmVzcyBzdWNjZXNzIGZhY3RvcnMgYXJlIHRoZWlyIGFkdmFuY2VkIG1vZGVscyB0aGF0IG1vdmUgYm9sZGx5IGF3YXkgZnJvbSB0cmFkaXRpb25hbCBhdXRvbW9iaWxlIHZlaGljbGVzIHdpdGggaXRzIHNwZWN0YWN1bGFyIGRlc2lnbiBhbmQgdW5pcXVlIGNhciB1c2VyIGV4cGVyaWVuY2UuIEhvd2V2ZXIsIHRoZSBwcmVtaXVtIGJyYW5kaW5nIG9mIHRoZSBUZXNsYSBFVnMgbWF5IGhhdmUgZGV0ZXJyZWQgbWFpbnN0cmVhbSBidXllcnMgZnJvbSBwdXJjaGFzaW5nIGEgRVYgbW9kZWwgZHVlIHRvIGEgbGFjayBvZiBhZmZvcmRhYmxlIGNoYXJnaW5nIHN0YXRpb25zLiAKCklmIHRoZSBVUyBtYXJrZXQgaW4gcGFydGljdWxhciB3YW50cyB0byBhY2hpZXZlIG1hc3MgRVYgYWRvcHRpb25zIGluIHRoZSBjb21pbmcgeWVhcnMsIHR3byB0eXBlcyBvZiBjdXN0b21lcnMgc2hvdWxkIGJlIGNvbnNpZGVyZWQuIE9uIHRoZSBvbmUgaGFuZCwgc29tZSBFViBlbnRodXNpYXN0cyBtYXkgYmUgb24gdGhlIGxvb2tvdXQgZm9yIFRlc2xhJ3MgYWR2YW5jZW1lbnQgaW4gYXV0b25vbW91cyB0ZWNobm9sb2d5IGFuZCBzZWxmLWRyaXZpbmcgdmVoaWNsZXMuIE9uIHRoZSBvdGhlciBoYW5kLCBzaW1pbGFyIHRvIHRyYWRpdGlvbmFsIGF1dG9tb2JpbGUgY3VzdG9tZXJzLCBhdmVyYWdlIEVWIGJ1eWVycyB3aG8gaGF2ZSB2YXJ5aW5nIG5lZWRzIGFuZCBiZWhhdmlvciBzaG91bGQgYmUgc3VwcGxpZWQgd2l0aCBhbiBlcXVhbGx5IGRpdmVyc2UgcmFuZ2Ugb2YgRVYgbW9kZWwgc2VsZWN0aW9ucywgd2hpY2ggaW4gdHVybiB3aWxsIHByb21wdCBtb3JlIGFmZm9yZGFibGUgY2hhcmdpbmcgc3RhdGlvbnMgYXZhaWxhYmxlIGluIGRpZmZlcmVudCBsb2NhdGlvbnMuIAoKYGBge3IgZWNobz1UUlVFfQpwMiA8LSBlbGVjdHJpY19kZiAlPiUgCiAgZmlsdGVyKGZyZXEgPiA0ODApICU+JQogIGdncGxvdChhZXMocmVvcmRlcih3b3JkLCBmcmVxKSwgZnJlcSwgZmlsbCA9ICIjMDg4MmM3aW5zIikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICNnZW9tX3RleHQoYWVzKGxhYmVsPXdvcmQsIHg9d29yZCwgeT0xODApLCBoanVzdCA9IDAsIGNvbG9yPSJ3aGl0ZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPWZyZXEsIHg9d29yZCwgeT0xMDApLCBoanVzdCA9IDEsIGNvbG9yPSJ3aGl0ZSIpICsgeGxhYihOVUxMKSArCiAgbGFicyh5ID0gIldvcmQgRnJlcXVlbmN5IikgKyAgY29vcmRfZmxpcCgpICsKICBnZ3RpdGxlKCJNb3N0IEZyZXF1ZW50IFRlcm1zIGluIEVsZWN0cmljYWwgVmVoaWNsZSBSZWxhdGVkIFR3ZWV0cyIpICsKICB0aGVtZV9jbGFzc2ljKCkKcDIKYGBgCgoKYGBge3IgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShxdWFudGVkYSkKcXVhbnRlZGFfY29ycHVzIDwtcXVhbnRlZGE6OmNvcnB1cyhlbGVjdHJpY19zdGVtbWVkKQpyZXF1aXJlKHF1YW50ZWRhKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CnBvcyA8LSByZWFkLnRhYmxlKCJwb3NpdGl2ZS13b3Jkcy50eHQiLCBhcy5pcz1UKQpuZWcgPC0gcmVhZC50YWJsZSgibmVnYXRpdmUtd29yZHMudHh0IiwgYXMuaXM9VCkKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpzZW50aW1lbnQgPC0gZnVuY3Rpb24od29yZHMpewogIHJlcXVpcmUocXVhbnRlZGEpCiAgdG9rIDwtIHF1YW50ZWRhOjp0b2tlbnMod29yZHMpCiAgcG9zLmNvdW50IDwtIHN1bSh0b2tbWzFdXSVpbiVwb3NbLDFdKQogIGNhdCgiXG4gcG9zaXRpdmUgd29yZHM6Iix0b2tbWzFdXVt3aGljaCh0b2tbWzFdXSVpbiVwb3NbLDFdKV0sIlxuIikKICBuZWcuY291bnQgPC0gc3VtKHRva1tbMV1dJWluJW5lZ1ssMV0pCiAgY2F0KCJcbiBuZWdhdGl2ZSB3b3JkczoiLHRva1tbMV1dW3doaWNoKHRva1tbMV1dJWluJW5lZ1ssMV0pXSwiXG4iKQogIG91dCA8LSAocG9zLmNvdW50IC0gbmVnLmNvdW50KS8ocG9zLmNvdW50K25lZy5jb3VudCkKICBjYXQoIlxuIFRvbmUgb2YgRG9jdW1lbnQ6IixvdXQpCiAgcmV0dXJuKG91dCkKfQoKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFIH0KcXVhbnRlZGFfZGYgPC0gZGF0YS5mcmFtZShxdWFudGVkYV9jb3JwdXMpCnF1YW50ZWRhX2RmJHRvbmUgPC0gYXBwbHkocXVhbnRlZGFfZGYsIDEsIGZ1bmN0aW9uKHgpe3NlbnRpbWVudCh4KX0pCnF1YW50ZWRhX2RmW2lzLm5hKHF1YW50ZWRhX2RmKV0gPSAwLjAKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpoZWFkKHF1YW50ZWRhX2RmKQpgYGAKCgoKCgoKIyMjIyAqKjMuMy4zIE1lYXN1cmluZyBjdXN0b21lciBwZXJjZXB0aW9ucyB0b3dhcmRzIEVWcyoqIAoKQXMgd2UgaGF2ZSBpZGVudGlmaWVkIGluIHRoZSBmYWN0b3IgYW5hbHlzaXMsIHdlIGh5cG90aGVzaXplIGN1c3RvbWVycyBob2xkIGEgcmVsYXRpdmVseSBwb3NpdGl2ZSB2aWV3IHRvd2FyZHMgdGhlIGVsZWN0cmljIG1vYmlsaXR5IGJ1c2luZXNzIGZvciBzZXZlcmFsIHJlYXNvbnM6IGZyb20gdGhlIHNoaWZ0aW5nIGZvY3VzIG9uIGdyZWVuaG91c2UgZ2FzIGVtaXNzaW9ucywgdG8gaW5jcmVhc2luZyBnb3Zlcm5tZW50IGludmVzdG1lbnQgZm9yIHB1YmxpYyBjaGFyZ2luZyBzdGF0aW9ucywgdG8gYSB2YXJpZXR5IG9mIEVWIG1vZGVscyBvZmZlcmVkLCB0byB0aGUgaW50cm9kdWN0aW9uIG9mIGJhdHRlcnkgbGVhc2luZyBhbmQgc3RvcmFnZS4gCgpUbyB0ZXN0IG91dCB0aGlzIGh5cG90aGVzaXMsIHdlIGNvbmR1Y3RlZCBhIHNlbnRpbWVudCBhbmFseXNpcyB0aGF0IGhpZ2hsaWdodHMgYSByZWxhdGl2ZWx5IHBvc2l0aXZlIHNlbnRpbWVudCBwYXR0ZXJuIG92ZXIgRVZzLiBEdXJpbmcgdGhlIDctZGF5IHR3aXR0ZXIgZXh0cmFjdGlvbiBwZXJpb2QsIHRoZSBudW1iZXIgb2YgcG9zaXRpdmUgdHdlZXRzIG91dHdlaWdoIHRoZSBudW1iZXIgb2YgbmVnYXRpdmUgdHdlZXRzOyBvdXQgb2YgdGhlIDExLDcwNiBwb3N0cyBleHRyYWN0ZWQsIHRoZSBtYWpvcml0eSBvZiBwb3N0cyBhcmUgaWRlbnRpZmllZCBhcyBuZXV0cmFsIHRvbmVzLiAgCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShwbG90bHkpCmNhdGVnb3J5X3NlbnQgPC0gaWZlbHNlKHF1YW50ZWRhX2RmJHRvbmUgPCAwLCAiTmVnYXRpdmUiLCBpZmVsc2UocXVhbnRlZGFfZGYkdG9uZSA+IDAsICJQb3NpdGl2ZSIsICJOZXV0cmFsIikpCnRvdGFscyA8LSBkYXRhLmZyYW1lKHRhYmxlKGNhdGVnb3J5X3NlbnQpKQpwbG90X2x5KHRvdGFscywgeCA9IH5jYXRlZ29yeV9zZW50LCB5ID0gfkZyZXEsIHR5cGUgPSAnYmFyJywKICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gYygnZ3JleScsICdvcmFuZ2UnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdwdXJwbGUnKSkpICU+JSBsYXlvdXQodGl0bGUgPSAnRWxlY3RyaWMgVmVoaWNsZSBUd2VldHMgYnkgU2VudGltZW50IGluIEFwcmlsIDIwMjEnKQoKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwb3NpdGl2ZV90b25lIDwtIHF1YW50ZWRhX2RmICU+JQogIGZpbHRlcih0b25lID09IDEpICU+JQogIG11dGF0ZShyYW5rPXJvd19udW1iZXIoKSkgCgpuZWdhdGl2ZV90b25lIDwtIHF1YW50ZWRhX2RmICU+JQogIGZpbHRlcih0b25lIDwgMCkgJT4lCiAgbXV0YXRlKHJhbms9cm93X251bWJlcigpKSAKYGBgCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeSh0ZXh0ZGF0YSkKc2VudGltZW50IDwtIGVsZWN0cmljX2RmICU+JQogICAgICBpbm5lcl9qb2luKGdldF9zZW50aW1lbnRzKCJiaW5nIikpIAoKaGVhZChzZW50aW1lbnQpCmBgYAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeSh0ZXh0ZGF0YSkKICAKc2VudGltZW50X3Bvc3RpdmUgPC0gc2VudGltZW50ICU+JQogIGZpbHRlcihzZW50aW1lbnQgPT0gInBvc2l0aXZlIikgJT4lCiAgYXJyYW5nZShkZXNjKGZyZXEpKQoKcG9zaXRpdmUgPC0gc2VudGltZW50X3Bvc3RpdmUgJT4lCiAgZmlsdGVyKGZyZXEgPiA4NSkKCnBvc2l0aXZlCmBgYAoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnNlbnRpbWVudF9uZWdhdGl2ZSA8LSBzZW50aW1lbnQgJT4lCiAgZmlsdGVyKHNlbnRpbWVudCA9PSAibmVnYXRpdmUiKSAlPiUKICBhcnJhbmdlKGRlc2MoZnJlcSkpCgpuZWdhdGl2ZSA8LSBzZW50aW1lbnRfbmVnYXRpdmUgJT4lCiAgZmlsdGVyKGZyZXEgPiAzNykKCm5lZ2F0aXZlCmBgYAoKCgoKCgojIyMjICoqMy4zLjQgVW5kZXJzdGFuZCB3aGF0IGluZGl2aWR1YWxzIGFyZSBhY3R1YWxseSB0YWxraW5nIGFib3V0IG9uIFR3aXR0ZXI/KioKCgoKKipQb3NpdGl2ZSBTZW50aW1lbnQqKjogQW1vbmcgdGhlIHBvc2l0aXZlIHR3ZWV0cywgYSBwb3NpdGl2ZSB0cmVuZCBpcyBpbGx1c3RyYXRlZCB0aHJvdWdoIGEgbGlzdCBvZiBoaWdoIGZyZXF1ZW5jeSB0ZXJtcyBzdWNoIGFzICJsaWtlIiwgICJncmVhdCIsICJnb29kIiwgImxvdmUiIGFuZCAiYmV0dGVyLiIgTW9yZSBzcGVjaWZpY2FsbHksICJjaGVhcGVyIiBhbmQgImFmZm9yZCIgYXJlIGFsc28gY2F0ZWdvcml6ZWQgYXMgcG9zaXRpdmUgd29yZHMsIGltcGx5aW5nIGEgbmFycm93aW5nIHByaWNlIGdhcCBhbmQgYSB3aWRlciByYW5nZSBvZiBhZmZvcmRhYmxlIG1vZGVscyBvZmZlcmVkIGluIHRoZSBnZW5lcmFsIEVWIG1hcmtldCB3aGljaCBhZ2FpbiBhbGlnbnMgd2l0aCBvdXIgcHJldmlvdXMgRVYgbW9kZWwgYW5hbHlzaXMuICAKCioqTmVnYXRpdmUgU2VudGltZW50Kio6IFRoZSBuZWdhdGl2ZSBzZW50aW1lbnQsIGluIGhpbmRzaWdodCwgaGVscHMgdG8gZGVwaWN0IGEgZGV0YWlsZWQgcG9ydHJhaXQgb2Ygd2hhdCBleGFjdGx5IGluZGl2aWR1YWxzIGFyZSBjb25jZXJuZWQgd2l0aC4gRmlyc3QsIHRoZSB0b3AgZnJlcXVlbmN5IHdvcmRzIHN1Y2ggYXMgImxpbWl0ZWQiIGFuZCAiZXhwYW5zaXZlIiBkZW1vbnN0cmF0ZXMgYSBzdHJvbmcgcHJlbWl1bSBicmFuZCBpbWFnZSBhdHRyaWJ1dGFibGUgdG8gVGVzbGEnIHMgbHV4dXJ5IG1vZGVsIHN1Y2Nlc3MuIEhvd2V2ZXIsIHRoaXMgY2xlYXIgYnJhbmQgaW1hZ2UgbWF5IGhhdmUgbGltaXRlZCB0aGUgZ3Jvd3RoIG9mIHRoZSBtYWluc3RyZWFtIEVWIG1hcmtldCBzaW5jZSBwb3RlbnRpYWwgY3VzdG9tZXJzIG1pZ2h0IHNoeSBhd2F5IGZyb20gcHVyY2hhc2luZyBhIEVWIGR1ZSB0byBwcmljZSBjb25jZXJucy4gQWRkaXRpb25hbGx5LCB3b3JkcyBsaWtlICJwcm9ibGVtIiBhbmQgImtpbGxlZCIgcG9zc2libHkgaW1wbHkgcG90ZW50aWFsIHNhZmV0eSBjb25jZXJucyB3aXRoIHJlZ2FyZHMgdG8gYmF0dGVyeSBxdWFsaXR5IGFuZCBhdXRvbm9tb3VzIHZlaGljbGUgYWNjaWRlbnRzLiBUbyB2ZXJpZnkgdGhlc2UgaW5zaWdodHMsIG1vcmUgdGV4dCBkYXRhIGFyZSByZXF1aXJlZCB0byB1bmRlcnN0YW5kIHdoZXRoZXIgY29uY2VybnMgdmFyeSBieSByZWdpb24gb3IgbWF5IGhhdmUgZXZvbHZlZCBvdmVydGltZS4gCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnBsb3Q0PC1wb3NpdGl2ZSAlPiUKICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcih3b3JkLCBmcmVxKSwgeSA9IGZyZXEpKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogICNzY2FsZV9maWxsX2Rpc2NyZXRlKCJTZW50aW1lbnQiLCBsYWJlbHMgPSBjKCJQb3NpdGl2ZSIsICJOZWdhdGl2ZSIpKSsKICBzY2FsZV9maWxsX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzPWMoIiMwMENFRDEiLCJmZjMzMDAiKSkgKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJsZWZ0IiwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSsKICBsYWJzKHg9IlR3aXR0ZXIgV29yZHMiLCB5PSJGcmVxdWVuY3kiLCB0aXRsZT0iUG9zaXRpdmUgU2VudGltZW50IikrCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41LCBzaXplPTIyKSkrCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTQpLGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9MTgpLCBheGlzLnRpdGxlLnk9IGVsZW1lbnRfdGV4dChzaXplPTE4KSkrCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9lY29ub21pc3QoKQoKcGxvdDU8LW5lZ2F0aXZlICU+JQogIGdncGxvdChhZXMoeD1yZW9yZGVyKHdvcmQsIGZyZXEpLCB5ID0gZnJlcSkpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrCiAgI3NjYWxlX2ZpbGxfZGlzY3JldGUoIlRvdGFsIGR1cmF0aW9uIG9mIEVWQSIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJmZjMzMDAiKSkrCiAgdGhlbWVfYncoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImxlZnQiLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNCkpKwogIGxhYnMoeD0iVHdpdHRlciBXb3JkcyIsIHk9IkZyZXF1ZW5jeSIsIHRpdGxlPSJOZWdhdGl2ZSBTZW50aW1lbnQiKSsKICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUsIHNpemU9MjIpKSsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xOCksIGF4aXMudGl0bGUueT0gZWxlbWVudF90ZXh0KHNpemU9MTgpKSsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2Vjb25vbWlzdCgpCnBsb3Q5PC1nZ2FycmFuZ2UocGxvdDQsIHBsb3Q1LCBucm93PTEsIG5jb2w9MikKcGxvdDkKCgoKYGBgCgoKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoc3l1emhldCkKc2NvcmUgPC0gZ2V0X25yY19zZW50aW1lbnQocXVhbnRlZGFfZGYkcXVhbnRlZGFfY29ycHVzKQpoZWFkKHNjb3JlKQpgYGAKIyMjIyAqKjMuMy41IEZvcndhcmQtbG9va2luZyBQZXJzcGVjdGl2ZTogVHdpdHRlciBFbW90aW9uIENsYXNzaWZpY2F0aW9uKioKCgoKV2hpbGUgdGhlIDctZGF5IFR3aXR0ZXIgZGF0YXNldCByZXZlYWxzIGEgcmVsYXRpdmVseSBwb3NpdGl2ZSB2aWV3IHRvd2FyZHMgRVZzLCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBleHBsb3JpbmcgdGhlIHByb3NwZWN0IG9mIGVsZWN0cmljIG1vYmlsaXR5IGFmdGVyIHRoZSBDT1ZJRC0xOSBjcmlzaXMuIE9uZSBwb3RlbnRpYWwgd2F5IGlzIHRvIGFuYWx5emUgaW5kaXZpZHVhbHMnIHZhcnlpbmcgZW1vdGlvbnM6IGZyb20gYW5nZXIsIHRvIGFudGljaXBhdGlvbiwgdG8gam95IAphbmQgZXRjLiBCYXNlZCBvbiB0aGUgZW1vdGlvbiBjbGFzc2lmaWNhdGlvbiBncmFwaCwgd2Ugd291bGQgbGlrZSB0byBoaWdobGlnaHQgdGhlIGZvbGxvd2luZyB0cmVuZHM6IAoKKipGZWFyIHZzIFRydXN0OiBEb2VzIHBlcmNlaXZlZCBiZW5lZml0cyBvZiBFVnMgb3V0d2VpZ2ggcGVyY2VpdmVkIGNvbmNlcm5zPyoqCkFjdHVhbCBwcm9kdWN0IG9mZmVyaW5nLCBpbiBmYWN0LCBjb3VsZCBkaWZmZXIgZnJvbSBjb25zdW1lciBwZXJjZWl2ZWQgcGVyc3BlY3RpdmVzOyB0aGVyZWZvcmUsIHRoZSBFViBidXNpbmVzcyBzaG91bGQgZW5zdXJlIGFsaWdubWVudCBiZXR3ZWVuIGl0cyBwcm9kdWN0IG9mZmVyaW5nIGFuZCBjdXN0b21lciBwZXJjZXB0aW9ucy4gSW4gdGhpcyBjYXNlLCB3ZSBzZWUgYSBmYWlybHkgcG9zaXRpdmUgc2lnbmFsIHRoYXQgY29uc3VtZXJzIHNlZW0gdG8gaGF2ZSBoaWdoZXIgInRydXN0IiB0aGFuICJmZWFyIiB0b3dhcmRzIHRoZSBlbGVjdHJpYyBtb2JpbGl0eSBtYXJrZXQuIFNwZWNpZmljYWxseSwgInRydXN0IiBjb3VsZCBzdGVtIGZyb20gaW1wcm92ZW1lbnQgaW4gYXV0b25vbW91cyB2ZWhpY2xlIHNhZmV0eSwgZWxldmF0ZWQgZm9jdXMgb24gZW1pc3Npb25zLCBhbmQgYmF0dGVyeSBxdWFsaXR5IHdoaWxlICJmZWFyIiBjb3VsZCBiZSBleHBsYWluZWQgYnkgdGhlIHVuY2VydGFpbnR5IGFyb3VuZCBjaGFyZ2luZyBpbmZyYXN0cnVjdHVyZSwgYmF0dGVyeSBxdWFsaXR5IGFuZCBtb2RlbCBhY2NpZGVudHMgdGhhdCBoYXZlIGJlZW4gZGlzY3Vzc2VkIGluIHByZXZpb3VzIGFuYWx5c2VzLiAgIAoKKipBbnRpY2lwYXRpb246IFdoYXQgb3Bwb3J0dW5pdGllcyBhcmUgcHJlc2VudCBpbiB0aGUgRVYgYnVzaW5lc3M/KiogCkFzIHRoZSBzZWNvbmQgaGlnaGVzdCBlbW90aW9uIHByZXNlbnQgaW4gdGhlIHNlbnRpbWVudCBhbmFseXNpcywgImFudGljaXBhdGlvbiIgaW1wbHkgYW1wbGUgZm9yd2FyZC1sb29raW5nIG9wcG9ydHVuaXRpZXMgc3VjaCBhcyBiYXR0ZXJ5IGxlYXNpbmcsIEVTRyBpbml0aWF0aXZlcyBhbmQgZnVydGhlciB0ZWNobm9sb2dpY2FsIGJyZWFrdGhyb3VnaC4gT3ZlcmFsbCwgY29uc3VtZXJzIGhvbGQgYSBmYWlybHkgb3B0aW1pc3RpYyB2aWV3IHRvd2FyZHMgdGhlIGZ1dHVyZSBvZiBlbGVjdHJpYyBtb2JpbGl0eSwgCgoKKipUd2l0dGVyIFNlbnRpbWVudCBBbmFseXNpcyBMaW1pdGF0aW9ucyoqIApTaW5jZSB3ZSBvbmx5IGhhdmUgYSBmcmVlIHR3aXR0ZXIgYWNjb3VudCwgd2UgY291bGQgb25seSByZXRyaWV2ZSA3LWRheSB0d2VldHMgZnJvbSB0aGUgQVBJOyBhIGxhcmdlciBkYXRhc2V0IHdvdWxkIGJlIG5lY2Vzc2FyeSB0byBnYWluIGEgbW9yZSBob2xpc3RpYyB1bmRlcnN0YW5kaW5nIG9mIHdoZXRoZXIgY29uc3VtZXIgcHJlZmVyZW5jZXMgaGF2ZSBzaGlmdGVkIGFmdGVyIHRoZSBDT1ZJRC0xOSBjcmlzaXMuIEZvciBpbnN0YW5jZSwgYSBjb21wYXJpc29uIGJldHdlZW4gMjAxOSBhbmQgMjAyMCB3b3VsZCBiZSByZWNvbW1lbmQuIEZ1cnRoZXIgYW5hbHlzaXMgY291bGQgYWxzbyBkZWx2ZSBkZWVwZXIgaW50byBob3cgZWxlY3RyaWMgbW9iaWxpdHkgdmFyeSBieSByZWdpb24gb3IgY291bnRyeS4gIAoKYGBge3IgZWNobz1GQUxTRX0KI3RyYW5zcG9zZQp0ZDwtZGF0YS5mcmFtZSh0KHNjb3JlKSkKdGRfbmV3IDwtIGRhdGEuZnJhbWUocm93U3Vtcyh0ZFsyOjI1M10pKQoKbmFtZXModGRfbmV3KVsxXSA8LSAiY291bnQiCnRkX25ldyA8LSBjYmluZCgic2VudGltZW50IiA9IHJvd25hbWVzKHRkX25ldyksIHRkX25ldykKcm93bmFtZXModGRfbmV3KSA8LSBOVUxMCnRkX25ldzI8LXRkX25ld1sxOjgsXQoKcXVpY2twbG90KHJlb3JkZXIoc2VudGltZW50LCBjb3VudCksIGRhdGE9dGRfbmV3Miwgd2VpZ2h0PWNvdW50LCBnZW9tPSJiYXIiLCBmaWxsPXNlbnRpbWVudCwgeWxhYj0iY291bnQiLHhsYWI9IlR3ZWV0IFNlbnRpbWVudCIpK2dndGl0bGUoIkVsZWN0cmljIFZlaGljbGUgVHdlZXQgU2VudGltZW50cyBpbiBBcHJpbCAyMDIxIikKYGBgCgo=