• 1. Introduction
    • 1.1 Abstract
    • 1.2 Motivation
    • 1.3 Theoretical Framework
    • 1.4 Methods
  • 2. Exploratory Analysis
    • 2.1 Crime Overview and Data Wrangling
    • 2.2 Feature Engineering
  • 3. Game Day Correlations
  • 4. Temporal Analysis
  • 5. Geospatial Analysis
    • 5.1 Lincoln Financial Field
    • 5.2 Bars
    • 5.3 SEPTA Stations
  • 6. Conclusion
    • 6.1 Results and Discussion
    • 6.2 Limitations and Further Research

1. Introduction

This project was completed as a Capstone Project by University of Pennsylvania graduate student Sean McClellan. The Master’s of Urban Spatial Analytics (MUSA) program is a one year program focused on data science, spatial analytics, statistics, GIS, and data visualization.

More information on the program can be found here. More of Sean’s work can be found here.

1.1 Abstract

NFL Football is a sport filled with passion and aggression. These qualities are shared by the fans. While passion at the stadium can make for a fun and competitive atmosphere, these qualities can just as easily result in antinormative behavior such as crime. For instance, assaults, vandalism, arrests for disorderly conduct, and arrests for alcohol-related offenses are all common arrests on football game days according to Rees & Schnepel (2009) which Deindividuation Theory would attribute to due to large crowds and stadium atmospheres. These settings and circumstances contribute to a collective mind, which can cause individuals to lose the ability of evaluating themselves or their actions and result in irrational or irresponsible behavior.

Exploring crime incidents across time and space in cities with professional football teams answers questions about the effect of NFL football on crime. Furthermore, patterns of spatial distribution and fluctuations in offense type totals can be connected to the result of that city’s team.

1.2 Motivation

Research has been conducted on this topic in the past, however most of this research has been strictly on levels of crime and included no spatial analysis. My project would fill this void by observing clustering and hot/cold spots of crime in each city. While the analysis will include basic measurements and comparisons of crime that is covered in previous research, this hot spot analysis will add a new component to NFL-related crime. I hypothesize that crime such as theft and assault will increase in density or cluster closer around each team’s stadium on game days. In addition to the spatial components of this analysis, it would be interesting to view scatter plots of points allowed by the home team and counts of crime, specifically violent crimes, to see if there is a correlation between performance and criminality.

1.3 Theoretical Framework

Game day related crime has been tied to multiple theories of crime and behavior. One of these theories, Routine Activity Theory, would best describe crime around Lincoln Financial Field on game days. Routine Activity Theory suggest crime occurs in situations where three things present themselves at the same time.

  1. A motivated offender
  2. A suitable target
  3. The absence of a capable guardian

Applying these three criteria to a stadium event could mean:

  1. An individual looking to steal an item from an unlocked vehicle
  2. Thousands of cars in stadium lots
  3. All car owners are in the stadium during the game

This very quickly and easily becomes an environment that welcomes criminal behavior, according to Routine Activity theory.

As mentioned in Section 1.2, the location of crime on game day lacks any significant amount of research, but Merlo et al. (2010) analyzed the average distance from the stadium that crime occurs within. Their results show that crime shifts closer to the stadium on game days, most likely due to tailgating and the dense and concentrated rush of people. On average, arrests made on game day occurred 0.69 miles from the stadium, while arrests happened an average of 2.1 miles away on non-game days (Merlo et al., 2010). A relation between game day and crime within a close radius of a stadium supports the hypothesis of Rees and Schnepel (2009) that opportunities for disputes and altercations unrelated to football increase as the population of the community temporarily increases. This means on game days it is reasonable to think the influx of people traveling to the game from areas outside of the Stadium District, a section of Philadelphia that is relatively empty on non-game days, could lead to disputes or altercations.

Both Rees & Schnepel (2009) and Merlo et al. (2010) found increases in arrests for alcohol possession by a minor, DUI, open container, and possession of alcohol in the stadium on game days. It is important to note that both of these studies were focused on NCAA Football and not NFL Football. While the findings from both studies are useful and significant, NFL teams, fan bases, stadiums, and cities present entirely new environments and possibly very different game day experiences.

1.4 Methods

This analysis will explain the connection between criminal incidents in the city of Philadelphia and the Philadelphia Eagles. Crime across the city will be subjected specific tests and figures showing concentration and clustering of crime around the stadium, bars, subway stops, and other local features. These crime levels and patterns can then be compared between other cities with NFL teams, painting a picture of how these teams affect their cities.

The methodology of this analysis will first include the gathering and cleaning of data. Working the datasets into desired formats will be vital to ensure data is ready for analysis despite being from many different sources. Then, data will need to be separated into home games and away games. This will be done by selecting only the observations in which the desired team is the home team. Once the NFL games have been wrangled, data from the city of Philadelphia can be brought into the analysis. Part I and Part II incidents were collected from the City of Philadelphia’s open data portal.

2. Exploratory Analysis

In this section, the data collected on NFL seasons and Philadelphia crime can be filtered and visualized in ways useful for this analysis. Again, this workflow could be easily adapted for another city, team, or year.

2.1 Crime Overview and Data Wrangling

Importing raw data for wrangling and cleaning includes reading basic NFL data which holds information on historical NFL games, scores, betting information, and more.

nfl <- read.csv("Data/spreadspoke_scores.csv") %>%
  filter(schedule_season == "2019")

# datatable(nfl, options = list(pageLength = 5,scrollX='400px'))
DT::datatable(nfl, options = list(pageLength = 5,scrollX='400px'))

Further data wrangling and cleaning can be completed by filtering this data to only include the teams included in this analysis. For instance, here is data extracted from the previous NFL data for only the Philadelphia Eagles.

eagles <- subset(nfl, team_home == "Philadelphia Eagles" | team_away == "Philadelphia Eagles") %>%
  mutate(date = mdy(schedule_date))

DT::datatable(eagles, options = list(pageLength = 5,scrollX='400px'))

These scores and game details will become useful later into the analysis. Crime data must be imported so game day crimes can be spatially compared to non-game day crimes. For now, let’s take a look at crime across the city for the entire year of 2019:

phlCrime <- read_sf("Philadelphia Eagles/incidents_part1_part2/incidents_part1_part2.shp") %>%
  st_transform('EPSG:3857') %>%
  mutate(date = ymd(dispatch_d),
         count = 1) %>%
  filter(point_y > 30)

df_sub <- phlCrime[1:100,]  # display the first 100 rows
df_sub$dispatch_t <- as.character(df_sub$dispatch_t) 
DT::datatable(df_sub, options = list(pageLength = 5,scrollX='400px'))
data <- phlCrime[1:10000,] # display the first 10,000 rows data$popup <- paste("Incident #: ", data$objectid, "
", "Description: ", data$text_gener, "
", "Date: ", data$dispatch_d, "
", "Time: ", data$dispatch_t, "
", "Longitude: ", data$point_x, "
", "Latitude: ", data$point_y) data %>% leaflet() %>% addTiles() %>% addTiles(group = "OSM (default)") %>% addProviderTiles(provider = "Esri.WorldStreetMap", group = "World StreetMap") %>% addProviderTiles(providers$CartoDB.Positron) %>% addMarkers(lng = ~point_x, lat = ~point_y, popup = data$popup, clusterOptions = markerClusterOptions())

Click the map to initialize

The figure above shows crime at multiple elevations. At the highest elevation, areas around Center City possess a staggering amount of crimes compared to the outer parts of the city. However, crime was a citywide issue in 2019. This is not new for Philadelphia. Crime in the city has been increasing each year, but what’s even more staggering is the types of crime pushing the totals so high. Violent crime has consistently been one of the highest categories in the recent past. Check out this interactive dashboard for Philadelphia’s shooting victimizations.

crime_cats <- phlCrime %>%
  mutate(category = case_when(
    text_gener == "Thefts" ~ "Thefts",
    text_gener == "Theft from Vehicle" ~ "Thefts",
    text_gener == "Aggravated Assault No Firearm" ~ "Violent", 
    text_gener == "Burglary Residential" ~ "Violent",
    text_gener == "Robbery No Firearm" ~ "Violent", 
    text_gener == "Burglary Non-Residential" ~ "Violent",
    text_gener == "Robbery Firearm" ~ "Violent",
    text_gener == "Rape" ~ "Rape",
    text_gener == "Aggravated Assault Firearm" ~ "Violent",
    text_gener == "Other Assaults" ~ "Violent",
    text_gener == "Narcotic / Drug Law Violations" ~ "Alcohol/Narcotics", 
    text_gener == "Weapon Violations" ~ "All Other Offenses",
    text_gener == "All Other Offenses" ~ "All Other Offenses",
    text_gener == "Vandalism/Criminal Mischief" ~ "All Other Offenses",
    text_gener == "DRIVING UNDER THE INFLUENCE" ~ "Alcohol/Narcotics",
    text_gener == "Fraud" ~ "Financial",
    text_gener == "Forgery and Counterfeiting" ~ "Financial",
    text_gener == "Embezzlement" ~ "Financial",
    text_gener == "Disorderly Conduct" ~ "All Other Offenses",
    text_gener == "Arson" ~ "All Other Offenses", 
    text_gener == "Offenses Against Family and Children" ~ "All Other Offenses",
    text_gener == "Other Sex Offenses (Not Commercialized)" ~ "Sex",
    text_gener == "Prostitution and Commercialized Vice" ~ "Sex",
    text_gener == "Public Drunkenness" ~ "Alcohol/Narcotics",
    text_gener == "Liquor Law Violations" ~ "Alcohol/Narcotics",
    text_gener == "Gambling Violations" ~ "All Other Offenses",
    text_gener == "Receiving Stolen Property" ~ "All Other Offenses",
    text_gener == "Vagrancy/Loitering" ~ "All Other Offenses",
    text_gener == "Homicide - Criminal" ~ "Homicide",
    text_gener == "Motor Vehicle Theft" ~ "Thefts"
  ))

phlCrime_counts <- crime_cats %>%
  group_by(category) %>%
  summarize(count=n()) %>%
  st_drop_geometry()

ggplot(data=phlCrime_counts,aes(x=reorder(category, -count), y=count)) +
  geom_bar(stat="identity", width=0.5, fill = "#0b465c") +
  labs(title = "2019 Crime by Offense Category", subtitle = "Philadelphia") +
  plotTheme

2.2 Feature Engineering

The types of crime, seen above, with the highest number of offenses were violent crimes and thefts. According to the research by Rees and Schnepel, thefts are known to increase during NFL home games. Where these crimes occur hold just as much importance as their offense category. There are multiple ways of portraying this data. Aggregating criminal incidents from 2019 to a fishnet grid gives an idea of where the most crime is occurring, similar to the interactive map above.

phlBound <- 
  st_read("http://data.phl.opendata.arcgis.com/datasets/063f5f85ef17468ebfebc1d2498b7daf_0.geojson") %>%
  st_transform('EPSG:3857')
## Reading layer `abf6322f-732c-41eb-be2f-a687a95d16462020329-1-11fkgla.x0gkf' from data source `http://data.phl.opendata.arcgis.com/datasets/063f5f85ef17468ebfebc1d2498b7daf_0.geojson' 
##   using driver `GeoJSON'
## Simple feature collection with 288 features and 4 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -75.28031 ymin: 39.86771 xmax: -74.95575 ymax: 40.13793
## Geodetic CRS:  WGS 84

phlOutline <- st_union(phlBound) %>%
  st_transform('EPSG:3857')

tracts <- st_read("Census_Tracts_2010.geojson") %>%
  st_transform("EPSG:3857")
## Reading layer `db894b56-81d3-49af-9fdf-8a4f8170db4f2020328-1-1i3f5cj.8z1e' from data source `/Users/seanmcclellan/Desktop/School/Capstone/Census_Tracts_2010.geojson' 
##   using driver `GeoJSON'
## Simple feature collection with 384 features and 14 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -75.28031 ymin: 39.86747 xmax: -74.95575 ymax: 40.13793
## Geodetic CRS:  WGS 84

stadiums <-
  st_read("Data/Stadiums/stadiums.json") %>%
  st_transform("EPSG:3857")
## Reading layer `stadiums' from data source 
##   `/Users/seanmcclellan/Desktop/School/Capstone/Data/Stadiums/stadiums.json' 
##   using driver `GeoJSON'
## Simple feature collection with 32 features and 6 fields
## Geometry type: POINT
## Dimension:     XY
## Bounding box:  xmin: -122.3317 ymin: 25.95806 xmax: -71.26344 ymax: 47.59528
## Geodetic CRS:  WGS 84

linc <- 
  stadiums %>%
  filter(Team == "Philadelphia Eagles")

lincBuffer <-
  st_buffer(linc, 1000) %>%
  st_transform(st_crs(stadiums))

septa_stops <- st_read("SEPTA_-_Highspeed_Stations.geojson") %>%
  st_transform("EPSG:3857") %>%
  st_filter(.,phlBound)
## Reading layer `SEPTA_-_Highspeed_Stations' from data source 
##   `/Users/seanmcclellan/Desktop/School/Capstone/SEPTA_-_Highspeed_Stations.geojson' 
##   using driver `GeoJSON'
## Simple feature collection with 74 features and 5 fields
## Geometry type: POINT
## Dimension:     XY
## Bounding box:  xmin: -75.35358 ymin: 39.90543 xmax: -75.07788 ymax: 40.11349
## Geodetic CRS:  WGS 84


septaBuffer <- 
    st_union(st_buffer(septa_stops, 275)) %>%
      st_sf() 

fishnetHexPhl <- 
  st_make_grid(phlBound,
               cellsize = 750, 
               square = FALSE) %>%
  .[phlBound] %>%            
  st_sf() %>%
  mutate(uniqueID = rownames(.))

crime_netHex <- 
  dplyr::select(phlCrime) %>% 
  mutate(countCrime = 1) %>% 
  aggregate(., fishnetHexPhl, sum) %>%
  mutate(countCrime = replace_na(countCrime, 0),
         uniqueID = rownames(.),
         cvID = sample(round(nrow(fishnetHexPhl) / 24), 
                       size=nrow(fishnetHexPhl), replace = TRUE))

ggplot() +
    geom_sf(data = crime_netHex, aes(fill = countCrime), color = "transparent", size = 0) +
    scale_fill_viridis()+
    labs(title = "Total Count of Crimes within Hex Grid",
        subtitle = "Philadelphia, PA - 2019") +
  mapTheme

crime_joined <- left_join(phlCrime, eagles, by = "date") %>%
  mutate(home_game = ifelse(team_home == "Philadelphia Eagles", 1, 0),
         away_game = ifelse(team_away == "Philadelphia Eagles", 1, 0),
         favorite = ifelse(team_favorite_id == "PHI", 1, 0),
         rivalry = ifelse(team_home == "Dallas Cowboys" | team_home == "Washington Redskins" |
                            team_home == "New York Giants" | team_away == "Dallas Cowboys" |
                            team_away == "Washington Redskins" | team_away == "New York Giants", 1, 0),
         gameday = ifelse(schedule_playoff == "TRUE" | schedule_playoff == "FALSE", 1, 0),
         dotw = wday(mdy(schedule_date)),
         total_points = score_home + score_away)

Plotting crime as point data, representative of each individual incident, provides a visual understanding that does not capture the true amount of events in a given area. Points can fall on top of each other when crimes throughout the year occur in the same place, or close enough in proximity to appear on the same location at a citywide elevation like above. Plotting the kernel density of crime, however, shows the same data while offering a better understanding of the spatial distribution of these incidents.

Separating crime into three categories will be the basis of the next component of analysis. Here, crimes from 2019 will be aggregated into three types of days: days with no Eagle’s game (NA), days on which the Eagle’s played at home (1), and days on which the Eagle’s played an away game (0).

ggplot() +
  geom_sf(data = crime_joined, color = "#165269", alpha = 0.25) +
  facet_wrap(~home_game) + 
  geom_sf(data = phlOutline, fill = "transparent", size = 1.25) +
  mapTheme



no_game <- crime_joined %>%
  filter(home_game != 1 | home_game != 0)

home_game <- crime_joined %>%
  filter(home_game == 1)

away_game <- crime_joined %>%
  filter(home_game == 0)

home_density <- 
  ggplot() + 
  geom_sf(data = phlOutline, fill = "grey40") +
  stat_density2d(data = data.frame(st_coordinates(home_game)), 
                 aes(X, Y, fill = ..level.., alpha = ..level..),
                 size = 0.01, bins = 40, geom = 'polygon') +
  scale_fill_viridis() +
  scale_alpha(range = c(0.00, 0.35), guide = FALSE) +
  labs(title = "Home Games") +
  mapTheme + 
  theme(legend.position = "none")

away_density <- 
  ggplot() + 
  geom_sf(data = phlOutline, fill = "grey40") +
  stat_density2d(data = data.frame(st_coordinates(away_game)), 
                 aes(X, Y, fill = ..level.., alpha = ..level..),
                 size = 0.01, bins = 40, geom = 'polygon') +
  scale_fill_viridis() +
  scale_alpha(range = c(0.00, 0.35), guide = FALSE) +
  labs(title = "Away Games") +
  mapTheme + 
  theme(legend.position = "none")

no_density <- 
  ggplot() + 
  geom_sf(data = phlOutline, fill = "grey40") +
  stat_density2d(data = data.frame(st_coordinates(no_game)), 
                 aes(X, Y, fill = ..level.., alpha = ..level..),
                 size = 0.01, bins = 40, geom = 'polygon') +
  scale_fill_viridis() +
  scale_alpha(range = c(0.00, 0.35), guide = FALSE) +
  labs(title = "No Games") +
  mapTheme + 
  theme(legend.position = "none")

grid.arrange(away_density,home_density,no_density, nrow = 1)

3. Game Day Correlations

Some of the research in this area has found that specific game day factors can influence crime during NCAA sporting events. Upset wins and losses, for instance, can influence criminality more than a normal win or loss.

Do these factors influence crime in Philadelphia?


corr_data <- read.csv("Data/spreadspoke_scores.csv") %>%
  filter(team_home == "Philadelphia Eagles" | team_away == "Philadelphia Eagles") %>%
  filter(schedule_season >= 2014) %>%
  mutate(date = mdy(schedule_date))

crime_2018 <- read_sf("Philadelphia Eagles/2018/incidents_part1_part2/incidents_part1_part2.shp") %>%
  st_transform('EPSG:3857') %>%
  mutate(date = ymd(dispatch_d),
         count = 1) %>%
  filter(point_y > 30)

crime_2017 <- read_sf("Philadelphia Eagles/2017/incidents_part1_part2/incidents_part1_part2.shp") %>%
  st_transform('EPSG:3857') %>%
  mutate(date = ymd(dispatch_d),
         count = 1) %>%
  filter(point_y > 30)

crime_2016 <- read_sf("Philadelphia Eagles/2016/incidents_part1_part2/incidents_part1_part2.shp") %>%
  st_transform('EPSG:3857') %>%
  mutate(date = ymd(dispatch_d),
         count = 1) %>%
  filter(point_y > 30)

crime_2015 <- read_sf("Philadelphia Eagles/2015/incidents_part1_part2/incidents_part1_part2.shp") %>%
  st_transform('EPSG:3857') %>%
  mutate(date = ymd(dispatch_d),
         count = 1) %>%
  filter(point_y > 30)

crime_2014 <- read_sf("Philadelphia Eagles/2014/incidents_part1_part2/incidents_part1_part2.shp") %>%
  st_transform('EPSG:3857') %>%
  mutate(date = ymd(dispatch_d),
         count = 1) %>%
  filter(point_y > 30)

all_crime <- do.call("rbind", list(phlCrime, crime_2018, crime_2017, crime_2016, crime_2015, crime_2014))

# EDIT - group by date AND hour? THIS DOESNT INCLUDE ZEROS - try complete(?)
crime_summary_hour <- all_crime %>%
  group_by(date, hour_) %>%
  summarize(crime_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date'. You can override using the
## `.groups` argument.

crime_summary_day <- all_crime %>%
  group_by(date) %>%
  summarize(daily_crime = sum(count)) %>%
  st_drop_geometry()

crime_summary_geo <- all_crime %>%
  group_by(date, hour_) %>%
  summarize(crime_per_hour = sum(count))
## `summarise()` has grouped output by 'date'. You can override using the
## `.groups` argument.


final_prep <- left_join(crime_summary_hour, corr_data, by = "date") %>%
  mutate(home_game = ifelse(team_home == "Philadelphia Eagles", 1, 0),
         away_game = ifelse(team_away == "Philadelphia Eagles", 1, 0),
         favorite = ifelse(team_favorite_id == "PHI", 1, 0),
         rivalry = ifelse(team_home == "Dallas Cowboys" | team_home == "Washington Redskins" |
                            team_home == "New York Giants" | team_away == "Dallas Cowboys" |
                            team_away == "Washington Redskins" | team_away == "New York Giants", 1, 0),
         gameday = ifelse(schedule_playoff == "TRUE" | schedule_playoff == "FALSE", 1, 0),
         dotw = wday(mdy(schedule_date)),
         total_points = score_home + score_away)

final <- left_join(final_prep, crime_summary_day, by = "date")
final_geo <- left_join(final_prep, crime_summary_geo, by = "date") %>%
  st_as_sf()

final$date <- as.numeric(final$date)

final_gameday <- final_geo %>%
  filter(gameday == 1)

corr <- 
  select_if(final, is.numeric) 
  
corr[is.na(corr)] <- 0

corr_gameday <- corr[, -c(1,2)] %>%
  filter(gameday == 1)

ggcorrplot(
  round(cor(corr_gameday), 1),
  p.mat = cor_pmat(corr_gameday),
  colors = c("#691652", "white", "#165269"),
  type="lower",
  insig = "blank") +  
  labs(title = "Correlation across numeric variables") +
  plotTheme

Total crime does not seem to be influenced by game day factors. This could be for a variety of reasons. Whereas the research that discovered connections between increases of crime and game days were conducted on NCAA teams in smaller towns, Philadelphia is one of the largest cities in the United States and experiences crime in a very different way than college towns.

The figure above suggests there are no significant correlations between game days or game day factors and the number of criminal incidents on a given day. However, if the same process is completed for specific crime categories, we see not much changes.

#EDIT - use corr instead of all crime?
all_categories <- all_crime %>%
  mutate(category = case_when(
    text_gener == "Thefts" ~ "Thefts",
    text_gener == "Theft from Vehicle" ~ "Thefts",
    text_gener == "Aggravated Assault No Firearm" ~ "Violent", 
    text_gener == "Burglary Residential" ~ "Violent",
    text_gener == "Robbery No Firearm" ~ "Violent", 
    text_gener == "Burglary Non-Residential" ~ "Violent",
    text_gener == "Robbery Firearm" ~ "Violent",
    text_gener == "Rape" ~ "Rape",
    text_gener == "Aggravated Assault Firearm" ~ "Violent",
    text_gener == "Other Assaults" ~ "Violent",
    text_gener == "Narcotic / Drug Law Violations" ~ "Alcohol/Narcotics", 
    text_gener == "Weapon Violations" ~ "All Other Offenses",
    text_gener == "All Other Offenses" ~ "All Other Offenses",
    text_gener == "Vandalism/Criminal Mischief" ~ "All Other Offenses",
    text_gener == "DRIVING UNDER THE INFLUENCE" ~ "Alcohol/Narcotics",
    text_gener == "Fraud" ~ "Financial",
    text_gener == "Forgery and Counterfeiting" ~ "Financial",
    text_gener == "Embezzlement" ~ "Financial",
    text_gener == "Disorderly Conduct" ~ "All Other Offenses",
    text_gener == "Arson" ~ "All Other Offenses", 
    text_gener == "Offenses Against Family and Children" ~ "All Other Offenses",
    text_gener == "Other Sex Offenses (Not Commercialized)" ~ "Sex",
    text_gener == "Prostitution and Commercialized Vice" ~ "Sex",
    text_gener == "Public Drunkenness" ~ "Alcohol/Narcotics",
    text_gener == "Liquor Law Violations" ~ "Alcohol/Narcotics",
    text_gener == "Gambling Violations" ~ "All Other Offenses",
    text_gener == "Receiving Stolen Property" ~ "All Other Offenses",
    text_gener == "Vagrancy/Loitering" ~ "All Other Offenses",
    text_gener == "Homicide - Criminal" ~ "Homicide",
    text_gener == "Motor Vehicle Theft" ~ "Thefts"
  ))
violent_crimes <- all_categories %>%
  filter(category == "Violent")

summary_violent <- violent_crimes %>%
  group_by(date) %>%
  summarize(crime_count = sum(count)) %>%
  st_drop_geometry()

final_violent <- left_join(summary_violent, corr_data, by = "date") %>%
  mutate(home_game = ifelse(team_home == "Philadelphia Eagles", 1, 0),
         away_game = ifelse(team_away == "Philadelphia Eagles", 1, 0),
         favorite = ifelse(team_favorite_id == "PHI", 1, 0),
         rivalry = ifelse(team_home == "Dallas Cowboys" | team_home == "Washington Redskins" |
                            team_home == "New York Giants" | team_away == "Dallas Cowboys" |
                            team_away == "Washington Redskins" | team_away == "New York Giants", 1, 0),
         gameday = ifelse(schedule_playoff == "TRUE" | schedule_playoff == "FALSE", 1, 0),
         dotw = wday(mdy(schedule_date)),
         total_points = score_home + score_away)

corr_violent <- 
  select_if(final_violent, is.numeric)

corr_violent[is.na(corr_violent)] <- 0

corr_violent %>%
  filter(gameday == 1)
## # A tibble: 101 × 16
##    crime_count schedule_season score_home score_away spread_favorite
##          <dbl>           <int>      <int>      <int>           <dbl>
##  1         138            2014         34         17           -10  
##  2         162            2014         27         30            -3  
##  3         146            2014         37         34            -4  
##  4         132            2014         26         21            -3.5
##  5         133            2014         34         28            -3.5
##  6         116            2014         27          0            -1  
##  7         119            2014         24         20            -1  
##  8         108            2014         21         31            -1.5
##  9         124            2014         45         21            -7  
## 10         102            2014         53         20            -4.5
## # … with 91 more rows, and 11 more variables: over_under_line <dbl>,
## #   weather_temperature <int>, weather_wind_mph <int>, weather_humidity <int>,
## #   home_game <dbl>, away_game <dbl>, favorite <dbl>, rivalry <dbl>,
## #   gameday <dbl>, dotw <dbl>, total_points <int>

ggcorrplot(
  round(cor(corr_violent), 1), 
  p.mat = cor_pmat(corr_violent),
  colors = c("#691652", "white", "#165269"),
  type="lower",
  insig = "blank") +  
  labs(title = "Violent Crimes") +
  plotTheme


# ALCOHOL

alc_narc_crimes <- all_categories %>%
  filter(category == "Alcohol/Narcotics")

summary_alc <- alc_narc_crimes %>%
  group_by(date) %>%
  summarize(crime_count = sum(count)) %>%
  st_drop_geometry()

final_alc <- left_join(summary_alc, corr_data, by = "date") %>%
  mutate(home_game = ifelse(team_home == "Philadelphia Eagles", 1, 0),
         away_game = ifelse(team_away == "Philadelphia Eagles", 1, 0),
         favorite = ifelse(team_favorite_id == "PHI", 1, 0),
         rivalry = ifelse(team_home == "Dallas Cowboys" | team_home == "Washington Redskins" |
                            team_home == "New York Giants" | team_away == "Dallas Cowboys" |
                            team_away == "Washington Redskins" | team_away == "New York Giants", 1, 0),
         gameday = ifelse(schedule_playoff == "TRUE" | schedule_playoff == "FALSE", 1, 0),
         dotw = wday(mdy(schedule_date)),
         total_points = score_home + score_away) 


corr_alc <- 
  select_if(final_alc, is.numeric)

corr_alc[is.na(corr_alc)] <- 0

corr_alc %>%
  filter(gameday == 1)
## # A tibble: 101 × 16
##    crime_count schedule_season score_home score_away spread_favorite
##          <dbl>           <int>      <int>      <int>           <dbl>
##  1          21            2014         34         17           -10  
##  2          32            2014         27         30            -3  
##  3          22            2014         37         34            -4  
##  4          24            2014         26         21            -3.5
##  5          28            2014         34         28            -3.5
##  6          30            2014         27          0            -1  
##  7          27            2014         24         20            -1  
##  8          24            2014         21         31            -1.5
##  9          25            2014         45         21            -7  
## 10          25            2014         53         20            -4.5
## # … with 91 more rows, and 11 more variables: over_under_line <dbl>,
## #   weather_temperature <int>, weather_wind_mph <int>, weather_humidity <int>,
## #   home_game <dbl>, away_game <dbl>, favorite <dbl>, rivalry <dbl>,
## #   gameday <dbl>, dotw <dbl>, total_points <int>

ggcorrplot(
  round(cor(corr_alc), 1), 
  p.mat = cor_pmat(corr_alc),
  colors = c("#691652", "white", "#165269"),
  type="lower",
  insig = "blank") +  
  labs(title = "Alcohol/Narcotics") +
  plotTheme


# THEFTS

theft_crimes <- all_categories %>%
  filter(category == "Thefts")

summary_theft <- theft_crimes %>%
  group_by(date) %>%
  summarize(crime_count = sum(count)) %>%
  st_drop_geometry()

final_theft <- left_join(summary_theft, corr_data, by = "date") %>%
  mutate(home_game = ifelse(team_home == "Philadelphia Eagles", 1, 0),
         away_game = ifelse(team_away == "Philadelphia Eagles", 1, 0),
         favorite = ifelse(team_favorite_id == "PHI", 1, 0),
         rivalry = ifelse(team_home == "Dallas Cowboys" | team_home == "Washington Redskins" |
                            team_home == "New York Giants" | team_away == "Dallas Cowboys" |
                            team_away == "Washington Redskins" | team_away == "New York Giants", 1, 0),
         gameday = ifelse(schedule_playoff == "TRUE" | schedule_playoff == "FALSE", 1, 0),
         dotw = wday(mdy(schedule_date)),
         total_points = score_home + score_away) 

corr_theft <- 
  select_if(final_theft, is.numeric)

corr_theft[is.na(corr_theft)] <- 0

corr_theft %>%
  filter(gameday == 1)
## # A tibble: 101 × 16
##    crime_count schedule_season score_home score_away spread_favorite
##          <dbl>           <int>      <int>      <int>           <dbl>
##  1         115            2014         34         17           -10  
##  2         124            2014         27         30            -3  
##  3         131            2014         37         34            -4  
##  4          97            2014         26         21            -3.5
##  5         114            2014         34         28            -3.5
##  6          93            2014         27          0            -1  
##  7         101            2014         24         20            -1  
##  8         105            2014         21         31            -1.5
##  9         138            2014         45         21            -7  
## 10          98            2014         53         20            -4.5
## # … with 91 more rows, and 11 more variables: over_under_line <dbl>,
## #   weather_temperature <int>, weather_wind_mph <int>, weather_humidity <int>,
## #   home_game <dbl>, away_game <dbl>, favorite <dbl>, rivalry <dbl>,
## #   gameday <dbl>, dotw <dbl>, total_points <int>

ggcorrplot(
  round(cor(corr_theft), 1), 
  p.mat = cor_pmat(corr_theft),
  colors = c("#691652", "white", "#165269"),
  type="lower",
  insig = "blank") +  
  labs(title = "Thefts") +
  plotTheme

4. Temporal Analysis

Since game day attributes do not seem to be significant, time is analyzed next.

all_time <- left_join(all_categories, corr_data, by = "date") %>%
  mutate(home_game = ifelse(team_home == "Philadelphia Eagles", 1, 0),
         away_game = ifelse(team_away == "Philadelphia Eagles", 1, 0),
         favorite = ifelse(team_favorite_id == "PHI", 1, 0),
         rivalry = ifelse(team_home == "Dallas Cowboys" | team_home == "Washington Redskins" |
                            team_home == "New York Giants" | team_away == "Dallas Cowboys" |
                            team_away == "Washington Redskins" | team_away == "New York Giants", 1, 0),
         gameday = ifelse(schedule_playoff == "TRUE" | schedule_playoff == "FALSE", 1, 0),
         dotw = wday(mdy(schedule_date)),
         total_points = score_home + score_away) 

library(viridis)
library(scales)

all_time %>%
  group_by(category, hour_) %>%
  summarise(count=n()) %>%
  ggplot(aes(x=category, y=hour_)) +
  geom_tile(aes(fill=count)) +
  labs(x="Crime Type", y = "Hour (0-23)", title="2014-2019 Total") +
  scale_fill_viridis_c("Number of Crimes",label=comma) +
  coord_flip()
## `summarise()` has grouped output by 'category'. You can override using the
## `.groups` argument.


all_time %>%
  filter(gameday == 1) %>%
  group_by(category,hour_) %>%
  summarise(count=n()) %>%
  ggplot(aes(x=category, y=hour_)) +
  geom_tile(aes(fill=count)) +
  labs(x="Crime Type", y = "Hour (0-23)", title="2014-2019 Gamedays") +
  scale_fill_viridis_c("Number of Crimes",label=comma) + 
  coord_flip()
## `summarise()` has grouped output by 'category'. You can override using the
## `.groups` argument.

crime_test <- crime_joined %>%
  group_by(date, gameday, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'gameday'. You can override using
## the `.groups` argument.

test_averages <- crime_test %>%
  group_by(hour_, gameday) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'hour_'. You can override using the
## `.groups` argument.

test_averages <- test_averages[-49,]
  
test_averages[is.na(test_averages)] <- 0


ggplot(test_averages, aes(x = hour_, y = avg_per_hour)) +
  geom_bar(stat = "identity") +
  facet_wrap(~gameday) +
  plotTheme

The figure above suggests overnight crimes are a bit more common (on average) on days with eagles games.

5. Geospatial Analysis

5.1 Lincoln Financial Field

We already know why crime would be likely to occur around a stadium, but here we will see how the Linc specifically relates to crime on game days.


# avg crime per hour on gamedays within buffer vs avg crime per hour within buffer on other days

linc_joined <- st_join(lincBuffer, all_categories, join = st_intersects)

linc_group <- left_join(linc_joined, corr_data, by = "date") %>%
  mutate(home_game = ifelse(team_home == "Philadelphia Eagles", 1, 0),
         away_game = ifelse(team_away == "Philadelphia Eagles", 1, 0),
         favorite = ifelse(team_favorite_id == "PHI", 1, 0),
         rivalry = ifelse(team_home == "Dallas Cowboys" | team_home == "Washington Redskins" |
                            team_home == "New York Giants" | team_away == "Dallas Cowboys" |
                            team_away == "Washington Redskins" | team_away == "New York Giants", 1, 0),
         gameday = ifelse(schedule_playoff == "TRUE" | schedule_playoff == "FALSE", 1, 0),
         dotw = wday(mdy(schedule_date)),
         total_points = score_home + score_away)

# SEPARATE BY GAMEDAY FIRST - facet wrap will use same scale.

linc_group2 <- linc_group %>%
  mutate(year = year(ymd(date)))

linc_prep <- linc_group %>%
  group_by(date, gameday, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'gameday'. You can override using
## the `.groups` argument.

linc_averages <- linc_prep %>%
  group_by(hour_, gameday) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'hour_'. You can override using the
## `.groups` argument.

# test_averages <- test_averages[-49,]
  
linc_averages[is.na(linc_averages)] <- 0

linc_table <- linc_averages %>%
  group_by(gameday) %>%
  summarize(per_hour_avg = mean(avg_per_hour))

# DT::datatable(linc_table, options = list(pageLength = 5,scrollX='400px'))
kable(linc_table, "simple")
gameday per_hour_avg
0 1.192926
1 1.279609

The table above shows that within 1000 meters of Lincoln Financial Field, the average number of crimes committed each hour is slightly higher on game days. The average city block in Philadelphia is about 400-500 feet. This means our buffer is around 7 or 8 blocks around the Linc. This is an interesting result as Lincoln Financial Field, as well as Philadelphia’s other professional sports stadiums (Wells Fargo Center and Citizens Bank Park), are in their own part of the city. This small of an increase, nearly 1.2 to 1.3 crimes per hour, is once again not consistent with previous research.

Let’s see if repeating this process for our three offense categories show any interesting results.

Note: The following line graphs do not include zero values

linc_cat_prep <- linc_group %>%
  group_by(date, gameday, category, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'gameday', 'category'. You can
## override using the `.groups` argument.

linc_cat_averages <- linc_cat_prep %>%
  group_by(hour_, gameday, category) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'hour_', 'gameday'. You can override using
## the `.groups` argument.

linc_cat_averages[is.na(linc_cat_averages)] <- 0

linc_cat_table <- linc_cat_averages %>%
  group_by(gameday,category) %>%
  summarize(per_hour_avg = mean(avg_per_hour))
## `summarise()` has grouped output by 'gameday'. You can override using the
## `.groups` argument.

ggplot(linc_cat_table, 
       aes(x = reorder(category, -per_hour_avg),
           y = per_hour_avg,
           color = as.factor(gameday),
           group = as.factor(gameday))) +
  geom_line() +
  geom_point() +
  scale_fill_viridis(discrete = TRUE) +
  scale_color_viridis(discrete = TRUE) +
  plotTheme +
  labs(title = "Average Crimes Per Hour Within 1000 m. of Lincoln Financial Field")+
  plotTheme

linc_cat_prep <- linc_group2 %>%
  group_by(date, year, gameday, category, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'year', 'gameday', 'category'. You
## can override using the `.groups` argument.

linc_cat_averages <- linc_cat_prep %>%
  group_by(year, hour_, gameday, category) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'year', 'hour_', 'gameday'. You can
## override using the `.groups` argument.

linc_cat_averages[is.na(linc_cat_averages)] <- 0

linc_cat_table <- linc_cat_averages %>%
  group_by(year,gameday,category) %>%
  summarize(per_hour_avg = mean(avg_per_hour))
## `summarise()` has grouped output by 'year', 'gameday'. You can override using
## the `.groups` argument.

ggplot(linc_cat_table, 
       aes(x = reorder(category, -per_hour_avg),
           y = per_hour_avg,
           color = as.factor(gameday),
           group = as.factor(gameday))) +
  geom_line() +
  geom_point() +
  scale_fill_viridis(discrete = TRUE) +
  scale_color_viridis(discrete = TRUE) +
  plotTheme +
  labs(title = "Average Crimes Per Hour Within 1000 m. of Lincoln Financial Field",
       subtitle = "By Year")+
  facet_wrap(~year, scales = "free")+
  plotTheme

5.2 Bars

Let’s see if average crimes per hour changes within 2 blocks of Philly bars and pubs.

bars <- st_read("data/pub_point.geojson") %>%
  st_transform("EPSG:3857") %>%
  st_as_sf()
## Reading layer `sql_statement' from data source 
##   `/Users/seanmcclellan/Desktop/School/Capstone/Data/pub_point.geojson' 
##   using driver `GeoJSON'
## Simple feature collection with 142 features and 23 fields
## Geometry type: POINT
## Dimension:     XY
## Bounding box:  xmin: -75.24387 ymin: 39.87382 xmax: -75.03771 ymax: 40.06808
## Geodetic CRS:  WGS 84

bar_buffer <-
  st_buffer(bars, 275) %>%
  st_union() %>%
  st_as_sf()

bars_joined <- st_join(bar_buffer, all_categories, join = st_intersects)

bar_group <- left_join(bars_joined, corr_data, by = "date") %>%
  mutate(home_game = ifelse(team_home == "Philadelphia Eagles", 1, 0),
         away_game = ifelse(team_away == "Philadelphia Eagles", 1, 0),
         favorite = ifelse(team_favorite_id == "PHI", 1, 0),
         rivalry = ifelse(team_home == "Dallas Cowboys" | team_home == "Washington Redskins" |
                            team_home == "New York Giants" | team_away == "Dallas Cowboys" |
                            team_away == "Washington Redskins" | team_away == "New York Giants", 1, 0),
         gameday = ifelse(schedule_playoff == "TRUE" | schedule_playoff == "FALSE", 1, 0),
         dotw = wday(mdy(schedule_date)),
         total_points = score_home + score_away)

bar_group2 <- bar_group %>%
  mutate(year = year(ymd(date)))

bar_prep <- bar_group %>%
  group_by(date, gameday, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'gameday'. You can override using
## the `.groups` argument.

bar_averages <- bar_prep %>%
  group_by(hour_, gameday) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'hour_'. You can override using the
## `.groups` argument.

# test_averages <- test_averages[-49,]
  
bar_averages[is.na(bar_averages)] <- 0

bar_table <- bar_averages %>%
  group_by(gameday) %>%
  summarize(per_hour_avg = mean(avg_per_hour))

# DT::datatable(bar_table, options = list(pageLength = 5,scrollX='400px'))
kable(bar_table, "simple")
gameday per_hour_avg
0 2.603614
1 2.273201

According to this analysis, bars are actually a bit safer on days of an Eagles game.

bar_cat_prep <- bar_group %>%
  group_by(date, gameday, category, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'gameday', 'category'. You can
## override using the `.groups` argument.

bar_cat_averages <- bar_cat_prep %>%
  group_by(hour_, gameday, category) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'hour_', 'gameday'. You can override using
## the `.groups` argument.

bar_cat_averages[is.na(bar_cat_averages)] <- 0

bar_cat_table <- bar_cat_averages %>%
  group_by(gameday,category) %>%
  summarize(per_hour_avg = mean(avg_per_hour))
## `summarise()` has grouped output by 'gameday'. You can override using the
## `.groups` argument.

ggplot(bar_cat_table, 
       aes(x = reorder(category, -per_hour_avg),
           y = per_hour_avg,
           color = as.factor(gameday),
           group = as.factor(gameday))) +
  geom_line() +
  geom_point() +
  scale_fill_viridis(discrete = TRUE) +
  scale_color_viridis(discrete = TRUE) +
  plotTheme +
  labs(title = "Average Crimes Per Hour Within 2 Blocks of Bars & Pubs")+
  plotTheme

bar_cat_prep <- bar_group2 %>%
  group_by(date, year, gameday, category, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'year', 'gameday', 'category'. You
## can override using the `.groups` argument.

bar_cat_averages <- bar_cat_prep %>%
  group_by(year, hour_, gameday, category) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'year', 'hour_', 'gameday'. You can
## override using the `.groups` argument.

bar_cat_averages[is.na(bar_cat_averages)] <- 0

bar_cat_table <- bar_cat_averages %>%
  group_by(year,gameday,category) %>%
  summarize(per_hour_avg = mean(avg_per_hour))
## `summarise()` has grouped output by 'year', 'gameday'. You can override using
## the `.groups` argument.

ggplot(bar_cat_table, 
       aes(x = reorder(category, -per_hour_avg),
           y = per_hour_avg,
           color = as.factor(gameday),
           group = as.factor(gameday))) +
  geom_line() +
  geom_point() +
  scale_fill_viridis(discrete = TRUE) +
  scale_color_viridis(discrete = TRUE) +
  plotTheme +
  labs(title = "Average Crimes Per Hour Within 2 Blocks of Bars & Pubs",
       subtitle = "By Year")+
  facet_wrap(~year, scales = "free")+
  plotTheme

5.3 SEPTA Stations

The final local feature in this assessment will be stations from SEPTA’s Broad Street and Market Frankford lines. First, let’s take a look at crime surrounding these stations for the entire year of 2019. Subway stops, and other transportation hubs, are known to be crime generators.

# crime_joined$ymd_hms <- paste(crime_joined$dispatch_d, crime_joined$dispatch_t)
# 
# cleaned_crime <- crime_joined %>%
#   mutate(interval60 = floor_date(ymd_hms(ymd_hms), unit = "hour"),
#          interval15 = floor_date(ymd_hms(ymd_hms), unit = "15 mins"))

gameday_tracts <- st_join(tracts, crime_joined, join = st_intersects)

tract_summary <- gameday_tracts %>%
  group_by(GEOID10) %>%
  summarize(crime_count = sum(count))

clip <- 
  st_intersection(septaBuffer, tract_summary) %>%
  dplyr::select(crime_count) %>%
  mutate(Selection_Type = "Clip")

qBr <- function(df, variable, rnd) {
  if (missing(rnd)) {
    as.character(quantile(round(df[[variable]],0),
                          c(.01,.2,.4,.6,.8), na.rm=T))
  } else if (rnd == FALSE | rnd == F) {
    as.character(formatC(quantile(df[[variable]]), digits = 3),
                 c(.01,.2,.4,.6,.8), na.rm=T)
  }
}

q5 <- function(variable) {as.factor(ntile(variable, 5))}

ggplot() +
  geom_sf(data=phlOutline) +
  geom_sf(data = tracts, size =0.2, color = "grey85", fill = "gray98") +
  geom_sf(data=clip, 
          aes(fill=q5(crime_count)), 
          color = "transparent") +
  scale_fill_viridis(discrete = TRUE, labels=qBr(clip,"crime_count"), 
                     name="Total Crime\n(Quintile Breaks)") +
  # scale_fill_manual(values=c("#2998C3","#2586AD","#207596","#1B6380","#165269"),
  #                   labels=qBr(clip,"crime_count"),
  #                   name="Total Crime\n(Quintile Breaks)")+
  geom_sf(data=phlOutline, fill = "transparent", size = 1) +
  # geom_sf(data = septa_stops, color = "white", size = 0.1) +
  labs(title="Total Crimes Within 500 m. of SEPTA Stops", 
       subtitle="2019") +
  mapTheme

septa_joined <- st_join(septaBuffer, all_categories, join = st_intersects)

septa_group <- left_join(septa_joined, corr_data, by = "date") %>%
  mutate(home_game = ifelse(team_home == "Philadelphia Eagles", 1, 0),
         away_game = ifelse(team_away == "Philadelphia Eagles", 1, 0),
         favorite = ifelse(team_favorite_id == "PHI", 1, 0),
         rivalry = ifelse(team_home == "Dallas Cowboys" | team_home == "Washington Redskins" |
                            team_home == "New York Giants" | team_away == "Dallas Cowboys" |
                            team_away == "Washington Redskins" | team_away == "New York Giants", 1, 0),
         gameday = ifelse(schedule_playoff == "TRUE" | schedule_playoff == "FALSE", 1, 0),
         dotw = wday(mdy(schedule_date)),
         total_points = score_home + score_away)

# SEPARATE BY GAMEDAY FIRST - facet wrap will use same scale.

septa_group2 <- septa_group %>%
  mutate(year = year(ymd(date)))

septa_prep <- septa_group %>%
  group_by(date, gameday, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'gameday'. You can override using
## the `.groups` argument.

septa_averages <- septa_prep %>%
  group_by(hour_, gameday) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'hour_'. You can override using the
## `.groups` argument.

# test_averages <- test_averages[-49,]
  
septa_averages[is.na(septa_averages)] <- 0

septa_table <- septa_averages %>%
  group_by(gameday) %>%
  summarize(per_hour_avg = mean(avg_per_hour))

# DT::datatable(septa_table, options = list(pageLength = 5,scrollX='400px'))
kable(septa_table, "simple")
gameday per_hour_avg
0 2.779927
1 2.435396
septa_cat_prep <- septa_group %>%
  group_by(date, gameday, category, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'gameday', 'category'. You can
## override using the `.groups` argument.

septa_cat_averages <- septa_cat_prep %>%
  group_by(hour_, gameday, category) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'hour_', 'gameday'. You can override using
## the `.groups` argument.

#ERROR - cant convert double to character?
septa_cat_averages <- as.data.frame(septa_cat_averages)
septa_cat_averages[is.na(septa_cat_averages)] = 0

septa_cat_table <- septa_cat_averages %>%
  group_by(gameday,category) %>%
  summarize(per_hour_avg = mean(avg_per_hour))
## `summarise()` has grouped output by 'gameday'. You can override using the
## `.groups` argument.

ggplot(septa_cat_table, 
       aes(x = reorder(category, -per_hour_avg),
           y = per_hour_avg,
           color = as.factor(gameday),
           group = as.factor(gameday))) +
  geom_line() +
  geom_point() +
  scale_fill_viridis(discrete = TRUE) +
  scale_color_viridis(discrete = TRUE) +
  plotTheme +
  labs(title = "Average Crimes Per Hour Within 2 Blocks of SEPTA Stops")+
  plotTheme

septa_cat_prep <- septa_group2 %>%
  group_by(date, year, gameday, category, hour_) %>%
  summarize(crimes_per_hour = sum(count)) %>%
  st_drop_geometry()
## `summarise()` has grouped output by 'date', 'year', 'gameday', 'category'. You
## can override using the `.groups` argument.

septa_cat_averages <- septa_cat_prep %>%
  group_by(year, hour_, gameday, category) %>%
  summarize(avg_per_hour = mean(crimes_per_hour))
## `summarise()` has grouped output by 'year', 'hour_', 'gameday'. You can
## override using the `.groups` argument.

septa_cat_averages <- as.data.frame(septa_cat_averages)
septa_cat_averages[is.na(septa_cat_averages)] <- 0

septa_cat_table <- septa_cat_averages %>%
  group_by(year,gameday,category) %>%
  summarize(per_hour_avg = mean(avg_per_hour))
## `summarise()` has grouped output by 'year', 'gameday'. You can override using
## the `.groups` argument.

ggplot(septa_cat_table, 
       aes(x = reorder(category, -per_hour_avg),
           y = per_hour_avg,
           color = as.factor(gameday),
           group = as.factor(gameday))) +
  geom_line() +
  geom_point() +
  scale_fill_viridis(discrete = TRUE) +
  scale_color_viridis(discrete = TRUE) +
  plotTheme +
  labs(title = "Average Crimes Per Hour Within 2 Blocks of SEPTA Stops",
       subtitle = "By Year")+
  facet_wrap(~year, scales = "free")+
  plotTheme

6. Conclusion

6.1 Results and Discussion

Repeating this analysis on another NFL team, perhaps a team in a smaller city, or a city where crime is less of a prevalent issue than it is in Philadelphia, could provide different results. Philadelphia has been experiencing increasing crime rates for quite a few years at this point. Pairing that recent trend with the fact that Philadelphia is one of the largest cities in the country offers an explanation as to why crime counts do not seem to change based on the presence of an Eagles game.

While some research has been completed on the relationship between crime and sports teams, only a few of these have dealt with professional sports, and even fewer have analyzed NFL Football. No research has been completed at this point that includes any geospatial analysis of this line of study.

In this geospatial analysis, I found increases (of varying levels) on game days in the following:

  • overall crime during overnight hours
  • total crime within 1000 meters of Lincoln Financial Field, specifically:
    • thefts
    • other unlisted offenses
    • financial offenses

and game day decreases in the following:

  • overall crime within 2 blocks of bars and pubs, specifically:
    • other unlisted offenses
    • violent crimes
    • alcoholic/narcotic offenses
  • overall crime within 2 blocks of SEPTA stations
    • other unlisted offenses
    • violent crimes
    • thefts

6.2 Limitations and Further Research

Further research should be done in this area with a more in depth comparison. For instance, instead of aggregating all non-game days from an entire year and comparing them to just 16 game days, only 8 of which are home games, a more selective approach could be conducted. To be sure this approach sets up a stronger and more fair comparison, the Sunday of each bye-week from the season could be used as a control. That way the seasonality changes play a minimal role in any variance.

If this were to be replicated and improved, additional analysis should be completed on the hours during a game, and for hours following a game. Additionally, this further analysis should be completed with respect to the different effects of home vs. away games. A stronger control or method of standardizing will likely produce results similar to those of the research mentioned in this report.

While this report was simply meant for explaining past events, correlations, and patterns, this type of analysis could absolutely serve a real purpose. If it was completed with a stronger control and comparison, there is no reason a college town couldn’t use this data in a predictive model from weekend to weekend. Knowing what factors influence crime increases, such as opponent, game start time, or time of year can be pivotal in smaller towns’ responses to crime. Obviously, the regular concerns of predictive policing would still apply and require the utmost caution and unbiased attention in designing such a model, but the use case is definitely existent.

LS0tCnRpdGxlOiAiVGhlIFBoaWxhZGVscGhpYSBFYWdsZXMnIEVmZmVjdCBvbiBDcmltZSIKYXV0aG9yOiAiU2VhbiBNY0NsZWxsYW4iCmRhdGU6ICcyMDIyLTAyLTI0JwpkZl9wcmludDogcGFnZWQKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvPVRSVUUsCiAgaW5jbHVkZT1UUlVFLAogIHdhcm5pbmc9RkFMU0UsCiAgbWVzc2FnZXM9RkFMU0UsCiAgZmlnLndpZHRoID0gOCwKICBmaWcua2VlcCA9ICdhbGwnLAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLAogIGNvbGxhcHNlPVRSVUUsCiAgY2FjaGU9VFJVRSwgCiAgYXV0b2RlcD1UUlVFLAogIGNhY2hlLmxhenkgPSBGQUxTRQogICkKb3B0aW9ucyhzY2lwZW49OTk5KQoKc2V0d2QoIi9Vc2Vycy9zZWFubWNjbGVsbGFuL0Rlc2t0b3AvU2Nob29sL0NhcHN0b25lIikKYGBgCgpgYGB7ciBsaWJyYXJpZXMsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShyZ2VvcykKbGlicmFyeSh0aWR5Y2Vuc3VzKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShEVCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KG1hcHZpZXcpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KGdnY29ycnBsb3QpCmxpYnJhcnkoZ2lmc2tpKQpsaWJyYXJ5KGdnYW5pbWF0ZSkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkod2lkZ2V0ZnJhbWUpCgptYXBUaGVtZSA8LSB0aGVtZShwbG90LnRpdGxlID1lbGVtZW50X3RleHQoc2l6ZT0xMiksCiAgICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwKICAgICAgICAgICAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgIGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvcj1lbGVtZW50X2xpbmUoY29sb3VyID0gJ3RyYW5zcGFyZW50JyksCiAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwgCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDEsIDEsIDEsIDEsICdjbScpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMSwgImNtIiksIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDAuMiwgImNtIikpCgpwbG90VGhlbWUgPC0gdGhlbWUoCiAgcGxvdC50aXRsZSA9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwKICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICMgU2V0IHRoZSBlbnRpcmUgY2hhcnQgcmVnaW9uIHRvIGJsYW5rCiAgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksCiAgcGxvdC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwKICAjcGFuZWwuYm9yZGVyPWVsZW1lbnRfcmVjdChjb2xvdXI9IiNGMEYwRjAiKSwKICAjIEZvcm1hdCB0aGUgZ3JpZAogIHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9saW5lKGNvbG91cj0iI0QwRDBEMCIsc2l6ZT0uMjUpLAogIGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpKQpgYGAKCiFbXShQaGlsYWRlbHBoaWEtRWFnbGVzLUxvZ28ucG5nKQoKIyAxLiBJbnRyb2R1Y3Rpb24KClRoaXMgcHJvamVjdCB3YXMgY29tcGxldGVkIGFzIGEgQ2Fwc3RvbmUgUHJvamVjdCBieSBVbml2ZXJzaXR5IG9mIFBlbm5zeWx2YW5pYSBncmFkdWF0ZSBzdHVkZW50IFNlYW4gTWNDbGVsbGFuLiBUaGUgTWFzdGVyJ3Mgb2YgVXJiYW4gU3BhdGlhbCBBbmFseXRpY3MgKE1VU0EpIHByb2dyYW0gaXMgYSBvbmUgeWVhciBwcm9ncmFtIGZvY3VzZWQgb24gZGF0YSBzY2llbmNlLCBzcGF0aWFsIGFuYWx5dGljcywgc3RhdGlzdGljcywgR0lTLCBhbmQgZGF0YSB2aXN1YWxpemF0aW9uLiAKCk1vcmUgaW5mb3JtYXRpb24gb24gdGhlIHByb2dyYW0gY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3d3dy5kZXNpZ24udXBlbm4uZWR1L211c2EvYWJvdXQpLgpNb3JlIG9mIFNlYW4ncyB3b3JrIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9zZWFubTQuZ2l0aHViLmlvKS4KCiMjIDEuMSBBYnN0cmFjdAoKTkZMIEZvb3RiYWxsIGlzIGEgc3BvcnQgZmlsbGVkIHdpdGggcGFzc2lvbiBhbmQgYWdncmVzc2lvbi4gVGhlc2UgcXVhbGl0aWVzIGFyZSBzaGFyZWQgYnkgdGhlIGZhbnMuIFdoaWxlIHBhc3Npb24gYXQgdGhlIHN0YWRpdW0gY2FuIG1ha2UgZm9yIGEgZnVuIGFuZCBjb21wZXRpdGl2ZSBhdG1vc3BoZXJlLCB0aGVzZSBxdWFsaXRpZXMgY2FuIGp1c3QgYXMgZWFzaWx5IHJlc3VsdCBpbiBhbnRpbm9ybWF0aXZlIGJlaGF2aW9yIHN1Y2ggYXMgY3JpbWUuIEZvciBpbnN0YW5jZSwgYXNzYXVsdHMsIHZhbmRhbGlzbSwgYXJyZXN0cyBmb3IgZGlzb3JkZXJseSBjb25kdWN0LCBhbmQgYXJyZXN0cyBmb3IgYWxjb2hvbC1yZWxhdGVkIG9mZmVuc2VzIGFyZSBhbGwgY29tbW9uIGFycmVzdHMgb24gZm9vdGJhbGwgZ2FtZSBkYXlzIGFjY29yZGluZyB0byBSZWVzICYgU2NobmVwZWwgKDIwMDkpIHdoaWNoIERlaW5kaXZpZHVhdGlvbiBUaGVvcnkgd291bGQgYXR0cmlidXRlIHRvIGR1ZSB0byBsYXJnZSBjcm93ZHMgYW5kIHN0YWRpdW0gYXRtb3NwaGVyZXMuIFRoZXNlIHNldHRpbmdzIGFuZCBjaXJjdW1zdGFuY2VzIGNvbnRyaWJ1dGUgdG8gYSBjb2xsZWN0aXZlIG1pbmQsIHdoaWNoIGNhbiBjYXVzZSBpbmRpdmlkdWFscyB0byBsb3NlIHRoZSBhYmlsaXR5IG9mIGV2YWx1YXRpbmcgdGhlbXNlbHZlcyBvciB0aGVpciBhY3Rpb25zIGFuZCByZXN1bHQgaW4gaXJyYXRpb25hbCBvciBpcnJlc3BvbnNpYmxlIGJlaGF2aW9yLgoKRXhwbG9yaW5nIGNyaW1lIGluY2lkZW50cyBhY3Jvc3MgdGltZSBhbmQgc3BhY2UgaW4gY2l0aWVzIHdpdGggcHJvZmVzc2lvbmFsIGZvb3RiYWxsIHRlYW1zIGFuc3dlcnMgcXVlc3Rpb25zIGFib3V0IHRoZSBlZmZlY3Qgb2YgTkZMIGZvb3RiYWxsIG9uIGNyaW1lLiBGdXJ0aGVybW9yZSwgcGF0dGVybnMgb2Ygc3BhdGlhbCBkaXN0cmlidXRpb24gYW5kIGZsdWN0dWF0aW9ucyBpbiBvZmZlbnNlIHR5cGUgdG90YWxzIGNhbiBiZSBjb25uZWN0ZWQgdG8gdGhlIHJlc3VsdCBvZiB0aGF0IGNpdHnigJlzIHRlYW0uIAoKIyMgMS4yIE1vdGl2YXRpb24KClJlc2VhcmNoIGhhcyBiZWVuIGNvbmR1Y3RlZCBvbiB0aGlzIHRvcGljIGluIHRoZSBwYXN0LCBob3dldmVyIG1vc3Qgb2YgdGhpcyByZXNlYXJjaCBoYXMgYmVlbiBzdHJpY3RseSBvbiBsZXZlbHMgb2YgY3JpbWUgYW5kIGluY2x1ZGVkIG5vIHNwYXRpYWwgYW5hbHlzaXMuIE15IHByb2plY3Qgd291bGQgZmlsbCB0aGlzIHZvaWQgYnkgb2JzZXJ2aW5nIGNsdXN0ZXJpbmcgYW5kIGhvdC9jb2xkIHNwb3RzIG9mIGNyaW1lIGluIGVhY2ggY2l0eS4gV2hpbGUgdGhlIGFuYWx5c2lzIHdpbGwgaW5jbHVkZSBiYXNpYyBtZWFzdXJlbWVudHMgYW5kIGNvbXBhcmlzb25zIG9mIGNyaW1lIHRoYXQgaXMgY292ZXJlZCBpbiBwcmV2aW91cyByZXNlYXJjaCwgdGhpcyBob3Qgc3BvdCBhbmFseXNpcyB3aWxsIGFkZCBhIG5ldyBjb21wb25lbnQgdG8gTkZMLXJlbGF0ZWQgY3JpbWUuIApJIGh5cG90aGVzaXplIHRoYXQgY3JpbWUgc3VjaCBhcyB0aGVmdCBhbmQgYXNzYXVsdCB3aWxsIGluY3JlYXNlIGluIGRlbnNpdHkgb3IgY2x1c3RlciBjbG9zZXIgYXJvdW5kIGVhY2ggdGVhbeKAmXMgc3RhZGl1bSBvbiBnYW1lIGRheXMuIEluIGFkZGl0aW9uIHRvIHRoZSBzcGF0aWFsIGNvbXBvbmVudHMgb2YgdGhpcyBhbmFseXNpcywgaXQgd291bGQgYmUgaW50ZXJlc3RpbmcgdG8gdmlldyBzY2F0dGVyIHBsb3RzIG9mIHBvaW50cyBhbGxvd2VkIGJ5IHRoZSBob21lIHRlYW0gYW5kIGNvdW50cyBvZiBjcmltZSwgc3BlY2lmaWNhbGx5IHZpb2xlbnQgY3JpbWVzLCB0byBzZWUgaWYgdGhlcmUgaXMgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBlcmZvcm1hbmNlIGFuZCBjcmltaW5hbGl0eS4KCiMjIDEuMyBUaGVvcmV0aWNhbCBGcmFtZXdvcmsKCkdhbWUgZGF5IHJlbGF0ZWQgY3JpbWUgaGFzIGJlZW4gdGllZCB0byBtdWx0aXBsZSB0aGVvcmllcyBvZiBjcmltZSBhbmQgYmVoYXZpb3IuIE9uZSBvZiB0aGVzZSB0aGVvcmllcywgUm91dGluZSBBY3Rpdml0eSBUaGVvcnksIHdvdWxkIGJlc3QgZGVzY3JpYmUgY3JpbWUgYXJvdW5kIExpbmNvbG4gRmluYW5jaWFsIEZpZWxkIG9uIGdhbWUgZGF5cy4gUm91dGluZSBBY3Rpdml0eSBUaGVvcnkgc3VnZ2VzdCBjcmltZSBvY2N1cnMgaW4gc2l0dWF0aW9ucyB3aGVyZSB0aHJlZSB0aGluZ3MgcHJlc2VudCB0aGVtc2VsdmVzIGF0IHRoZSBzYW1lIHRpbWUuIAoKMS4gQSBtb3RpdmF0ZWQgb2ZmZW5kZXIKMi4gQSBzdWl0YWJsZSB0YXJnZXQKMy4gVGhlIGFic2VuY2Ugb2YgYSBjYXBhYmxlIGd1YXJkaWFuCgpBcHBseWluZyB0aGVzZSB0aHJlZSBjcml0ZXJpYSB0byBhIHN0YWRpdW0gZXZlbnQgY291bGQgbWVhbjoKCjEuIEFuIGluZGl2aWR1YWwgbG9va2luZyB0byBzdGVhbCBhbiBpdGVtIGZyb20gYW4gdW5sb2NrZWQgdmVoaWNsZQoyLiBUaG91c2FuZHMgb2YgY2FycyBpbiBzdGFkaXVtIGxvdHMKMy4gQWxsIGNhciBvd25lcnMgYXJlIGluIHRoZSBzdGFkaXVtIGR1cmluZyB0aGUgZ2FtZQoKVGhpcyB2ZXJ5IHF1aWNrbHkgYW5kIGVhc2lseSBiZWNvbWVzIGFuIGVudmlyb25tZW50IHRoYXQgd2VsY29tZXMgY3JpbWluYWwgYmVoYXZpb3IsIGFjY29yZGluZyB0byBSb3V0aW5lIEFjdGl2aXR5IHRoZW9yeS4KCkFzIG1lbnRpb25lZCBpbiBTZWN0aW9uIDEuMiwgdGhlIGxvY2F0aW9uIG9mIGNyaW1lIG9uIGdhbWUgZGF5IGxhY2tzIGFueSBzaWduaWZpY2FudCBhbW91bnQgb2YgcmVzZWFyY2gsIGJ1dCBNZXJsbyBldCBhbC4gKDIwMTApIGFuYWx5emVkIHRoZSBhdmVyYWdlIGRpc3RhbmNlIGZyb20gdGhlIHN0YWRpdW0gdGhhdCBjcmltZSBvY2N1cnMgd2l0aGluLiBUaGVpciByZXN1bHRzIHNob3cgdGhhdCBjcmltZSBzaGlmdHMgY2xvc2VyIHRvIHRoZSBzdGFkaXVtIG9uIGdhbWUgZGF5cywgbW9zdCBsaWtlbHkgZHVlIHRvIHRhaWxnYXRpbmcgYW5kIHRoZSBkZW5zZSBhbmQgY29uY2VudHJhdGVkIHJ1c2ggb2YgcGVvcGxlLiBPbiBhdmVyYWdlLCBhcnJlc3RzIG1hZGUgb24gZ2FtZSBkYXkgb2NjdXJyZWQgMC42OSBtaWxlcyBmcm9tIHRoZSBzdGFkaXVtLCB3aGlsZSBhcnJlc3RzIGhhcHBlbmVkIGFuIGF2ZXJhZ2Ugb2YgMi4xIG1pbGVzIGF3YXkgb24gbm9uLWdhbWUgZGF5cyAoTWVybG8gZXQgYWwuLCAyMDEwKS4gQSByZWxhdGlvbiBiZXR3ZWVuIGdhbWUgZGF5IGFuZCBjcmltZSB3aXRoaW4gYSBjbG9zZSByYWRpdXMgb2YgYSBzdGFkaXVtIHN1cHBvcnRzIHRoZSBoeXBvdGhlc2lzIG9mIFJlZXMgYW5kIFNjaG5lcGVsICgyMDA5KSB0aGF0IG9wcG9ydHVuaXRpZXMgZm9yIGRpc3B1dGVzIGFuZCBhbHRlcmNhdGlvbnMgdW5yZWxhdGVkIHRvIGZvb3RiYWxsIGluY3JlYXNlIGFzIHRoZSBwb3B1bGF0aW9uIG9mIHRoZSBjb21tdW5pdHkgdGVtcG9yYXJpbHkgaW5jcmVhc2VzLiBUaGlzIG1lYW5zIG9uIGdhbWUgZGF5cyBpdCBpcyByZWFzb25hYmxlIHRvIHRoaW5rIHRoZSBpbmZsdXggb2YgcGVvcGxlIHRyYXZlbGluZyB0byB0aGUgZ2FtZSBmcm9tIGFyZWFzIG91dHNpZGUgb2YgdGhlIFN0YWRpdW0gRGlzdHJpY3QsIGEgc2VjdGlvbiBvZiBQaGlsYWRlbHBoaWEgdGhhdCBpcyByZWxhdGl2ZWx5IGVtcHR5IG9uIG5vbi1nYW1lIGRheXMsIGNvdWxkIGxlYWQgdG8gZGlzcHV0ZXMgb3IgYWx0ZXJjYXRpb25zLiAKCkJvdGggUmVlcyAmIFNjaG5lcGVsICgyMDA5KSBhbmQgTWVybG8gZXQgYWwuICgyMDEwKSBmb3VuZCBpbmNyZWFzZXMgaW4gYXJyZXN0cyBmb3IgYWxjb2hvbCBwb3NzZXNzaW9uIGJ5IGEgbWlub3IsIERVSSwgb3BlbiBjb250YWluZXIsIGFuZCBwb3NzZXNzaW9uIG9mIGFsY29ob2wgaW4gdGhlIHN0YWRpdW0gb24gZ2FtZSBkYXlzLiBJdCBpcyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IGJvdGggb2YgdGhlc2Ugc3R1ZGllcyB3ZXJlIGZvY3VzZWQgb24gTkNBQSBGb290YmFsbCBhbmQgbm90IE5GTCBGb290YmFsbC4gV2hpbGUgdGhlIGZpbmRpbmdzIGZyb20gYm90aCBzdHVkaWVzIGFyZSB1c2VmdWwgYW5kIHNpZ25pZmljYW50LCBORkwgdGVhbXMsIGZhbiBiYXNlcywgc3RhZGl1bXMsIGFuZCBjaXRpZXMgcHJlc2VudCBlbnRpcmVseSBuZXcgZW52aXJvbm1lbnRzIGFuZCBwb3NzaWJseSB2ZXJ5IGRpZmZlcmVudCBnYW1lIGRheSBleHBlcmllbmNlcy4KCgoKIyMgMS40IE1ldGhvZHMKClRoaXMgYW5hbHlzaXMgd2lsbCBleHBsYWluIHRoZSBjb25uZWN0aW9uIGJldHdlZW4gY3JpbWluYWwgaW5jaWRlbnRzIGluIHRoZSBjaXR5IG9mIFBoaWxhZGVscGhpYSBhbmQgdGhlIFBoaWxhZGVscGhpYSBFYWdsZXMuIENyaW1lIGFjcm9zcyB0aGUgY2l0eSB3aWxsIGJlIHN1YmplY3RlZCBzcGVjaWZpYyB0ZXN0cyBhbmQgZmlndXJlcyBzaG93aW5nIGNvbmNlbnRyYXRpb24gYW5kIGNsdXN0ZXJpbmcgb2YgY3JpbWUgYXJvdW5kIHRoZSBzdGFkaXVtLCBiYXJzLCBzdWJ3YXkgc3RvcHMsIGFuZCBvdGhlciBsb2NhbCBmZWF0dXJlcy4gVGhlc2UgY3JpbWUgbGV2ZWxzIGFuZCBwYXR0ZXJucyBjYW4gdGhlbiBiZSBjb21wYXJlZCBiZXR3ZWVuIG90aGVyIGNpdGllcyB3aXRoIE5GTCB0ZWFtcywgcGFpbnRpbmcgYSBwaWN0dXJlIG9mIGhvdyB0aGVzZSB0ZWFtcyBhZmZlY3QgdGhlaXIgY2l0aWVzLgoKVGhlIG1ldGhvZG9sb2d5IG9mIHRoaXMgYW5hbHlzaXMgd2lsbCBmaXJzdCBpbmNsdWRlIHRoZSBnYXRoZXJpbmcgYW5kIGNsZWFuaW5nIG9mIGRhdGEuIFdvcmtpbmcgdGhlIGRhdGFzZXRzIGludG8gZGVzaXJlZCBmb3JtYXRzIHdpbGwgYmUgdml0YWwgdG8gZW5zdXJlIGRhdGEgaXMgcmVhZHkgZm9yIGFuYWx5c2lzIGRlc3BpdGUgYmVpbmcgZnJvbSBtYW55IGRpZmZlcmVudCBzb3VyY2VzLiBUaGVuLCBkYXRhIHdpbGwgbmVlZCB0byBiZSBzZXBhcmF0ZWQgaW50byBob21lIGdhbWVzIGFuZCBhd2F5IGdhbWVzLiBUaGlzIHdpbGwgYmUgZG9uZSBieSBzZWxlY3Rpbmcgb25seSB0aGUgb2JzZXJ2YXRpb25zIGluIHdoaWNoIHRoZSBkZXNpcmVkIHRlYW0gaXMgdGhlIGhvbWUgdGVhbS4gT25jZSB0aGUgTkZMIGdhbWVzIGhhdmUgYmVlbiB3cmFuZ2xlZCwgZGF0YSBmcm9tIHRoZSBjaXR5IG9mIFBoaWxhZGVscGhpYSBjYW4gYmUgYnJvdWdodCBpbnRvIHRoZSBhbmFseXNpcy4gUGFydCBJIGFuZCBQYXJ0IElJIGluY2lkZW50cyB3ZXJlIGNvbGxlY3RlZCBmcm9tIHRoZSBDaXR5IG9mIFBoaWxhZGVscGhpYSdzIFtvcGVuIGRhdGEgcG9ydGFsXShodHRwczovL3d3dy5vcGVuZGF0YXBoaWxseS5vcmcpLgoKCgojIDIuIEV4cGxvcmF0b3J5IEFuYWx5c2lzCgpJbiB0aGlzIHNlY3Rpb24sIHRoZSBkYXRhIGNvbGxlY3RlZCBvbiBORkwgc2Vhc29ucyBhbmQgUGhpbGFkZWxwaGlhIGNyaW1lIGNhbiBiZSBmaWx0ZXJlZCBhbmQgdmlzdWFsaXplZCBpbiB3YXlzIHVzZWZ1bCBmb3IgdGhpcyBhbmFseXNpcy4gQWdhaW4sIHRoaXMgd29ya2Zsb3cgY291bGQgYmUgZWFzaWx5IGFkYXB0ZWQgZm9yIGFub3RoZXIgY2l0eSwgdGVhbSwgb3IgeWVhci4gCgojIyAyLjEgQ3JpbWUgT3ZlcnZpZXcgYW5kIERhdGEgV3JhbmdsaW5nCgpJbXBvcnRpbmcgcmF3IGRhdGEgZm9yIHdyYW5nbGluZyBhbmQgY2xlYW5pbmcgaW5jbHVkZXMgcmVhZGluZyBiYXNpYyBORkwgZGF0YSB3aGljaCBob2xkcyBpbmZvcm1hdGlvbiBvbiBoaXN0b3JpY2FsIE5GTCBnYW1lcywgc2NvcmVzLCBiZXR0aW5nIGluZm9ybWF0aW9uLCBhbmQgbW9yZS4gCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9Cm5mbCA8LSByZWFkLmNzdigiRGF0YS9zcHJlYWRzcG9rZV9zY29yZXMuY3N2IikgJT4lCiAgZmlsdGVyKHNjaGVkdWxlX3NlYXNvbiA9PSAiMjAxOSIpCgojIGRhdGF0YWJsZShuZmwsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1LHNjcm9sbFg9JzQwMHB4JykpCkRUOjpkYXRhdGFibGUobmZsLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSxzY3JvbGxYPSc0MDBweCcpKQpgYGAKCkZ1cnRoZXIgZGF0YSB3cmFuZ2xpbmcgYW5kIGNsZWFuaW5nIGNhbiBiZSBjb21wbGV0ZWQgYnkgZmlsdGVyaW5nIHRoaXMgZGF0YSB0byBvbmx5IGluY2x1ZGUgdGhlIHRlYW1zIGluY2x1ZGVkIGluIHRoaXMgYW5hbHlzaXMuIEZvciBpbnN0YW5jZSwgaGVyZSBpcyBkYXRhIGV4dHJhY3RlZCBmcm9tIHRoZSBwcmV2aW91cyBORkwgZGF0YSBmb3Igb25seSB0aGUgUGhpbGFkZWxwaGlhIEVhZ2xlcy4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KZWFnbGVzIDwtIHN1YnNldChuZmwsIHRlYW1faG9tZSA9PSAiUGhpbGFkZWxwaGlhIEVhZ2xlcyIgfCB0ZWFtX2F3YXkgPT0gIlBoaWxhZGVscGhpYSBFYWdsZXMiKSAlPiUKICBtdXRhdGUoZGF0ZSA9IG1keShzY2hlZHVsZV9kYXRlKSkKCkRUOjpkYXRhdGFibGUoZWFnbGVzLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSxzY3JvbGxYPSc0MDBweCcpKQpgYGAKClRoZXNlIHNjb3JlcyBhbmQgZ2FtZSBkZXRhaWxzIHdpbGwgYmVjb21lIHVzZWZ1bCBsYXRlciBpbnRvIHRoZSBhbmFseXNpcy4gQ3JpbWUgZGF0YSBtdXN0IGJlIGltcG9ydGVkIHNvIGdhbWUgZGF5IGNyaW1lcyBjYW4gYmUgc3BhdGlhbGx5IGNvbXBhcmVkIHRvIG5vbi1nYW1lIGRheSBjcmltZXMuIEZvciBub3csIGxldCdzIHRha2UgYSBsb29rIGF0IGNyaW1lIGFjcm9zcyB0aGUgY2l0eSBmb3IgdGhlIGVudGlyZSB5ZWFyIG9mIDIwMTk6CgpgYGB7ciwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CnBobENyaW1lIDwtIHJlYWRfc2YoIlBoaWxhZGVscGhpYSBFYWdsZXMvaW5jaWRlbnRzX3BhcnQxX3BhcnQyL2luY2lkZW50c19wYXJ0MV9wYXJ0Mi5zaHAiKSAlPiUKICBzdF90cmFuc2Zvcm0oJ0VQU0c6Mzg1NycpICU+JQogIG11dGF0ZShkYXRlID0geW1kKGRpc3BhdGNoX2QpLAogICAgICAgICBjb3VudCA9IDEpICU+JQogIGZpbHRlcihwb2ludF95ID4gMzApCgpkZl9zdWIgPC0gcGhsQ3JpbWVbMToxMDAsXSAgIyBkaXNwbGF5IHRoZSBmaXJzdCAxMDAgcm93cwpkZl9zdWIkZGlzcGF0Y2hfdCA8LSBhcy5jaGFyYWN0ZXIoZGZfc3ViJGRpc3BhdGNoX3QpIApEVDo6ZGF0YXRhYmxlKGRmX3N1Yiwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDUsc2Nyb2xsWD0nNDAwcHgnKSkKCmRhdGEgPC0gcGhsQ3JpbWVbMToxMDAwMCxdICMgZGlzcGxheSB0aGUgZmlyc3QgMTAsMDAwIHJvd3MKZGF0YSRwb3B1cCA8LSBwYXN0ZSgiPGI+SW5jaWRlbnQgIzogPC9iPiIsIGRhdGEkb2JqZWN0aWQsIAogICAgICAgICAgICAgICAgICAgICI8YnI+IiwgIjxiPkRlc2NyaXB0aW9uOiA8L2I+IiwgZGF0YSR0ZXh0X2dlbmVyLAogICAgICAgICAgICAgICAgICAgICI8YnI+IiwgIjxiPkRhdGU6IDwvYj4iLCBkYXRhJGRpc3BhdGNoX2QsCiAgICAgICAgICAgICAgICAgICAgIjxicj4iLCAiPGI+VGltZTogPC9iPiIsIGRhdGEkZGlzcGF0Y2hfdCwKICAgICAgICAgICAgICAgICAgICAiPGJyPiIsICI8Yj5Mb25naXR1ZGU6IDwvYj4iLCBkYXRhJHBvaW50X3gsCiAgICAgICAgICAgICAgICAgICAgIjxicj4iLCAiPGI+TGF0aXR1ZGU6IDwvYj4iLCBkYXRhJHBvaW50X3kpCmRhdGEgJT4lCiAgbGVhZmxldCgpICU+JSAKICBhZGRUaWxlcygpICU+JQogICAgYWRkVGlsZXMoZ3JvdXAgPSAiT1NNIChkZWZhdWx0KSIpICU+JQogICAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlciA9ICJFc3JpLldvcmxkU3RyZWV0TWFwIiwgCiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSAiV29ybGQgU3RyZWV0TWFwIikgJT4lCiAgICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUKICAgIGFkZE1hcmtlcnMobG5nID0gfnBvaW50X3gsIGxhdCA9IH5wb2ludF95LCBwb3B1cCA9IGRhdGEkcG9wdXAsIAogICAgICAgICAgICAgIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoKSkKYGBgCgoqKkNsaWNrIHRoZSBtYXAgdG8gaW5pdGlhbGl6ZSoqCgoKVGhlIGZpZ3VyZSBhYm92ZSBzaG93cyBjcmltZSBhdCBtdWx0aXBsZSBlbGV2YXRpb25zLiBBdCB0aGUgaGlnaGVzdCBlbGV2YXRpb24sIGFyZWFzIGFyb3VuZCBDZW50ZXIgQ2l0eSBwb3NzZXNzIGEgc3RhZ2dlcmluZyBhbW91bnQgb2YgY3JpbWVzIGNvbXBhcmVkIHRvIHRoZSBvdXRlciBwYXJ0cyBvZiB0aGUgY2l0eS4gSG93ZXZlciwgY3JpbWUgd2FzIGEgY2l0eXdpZGUgaXNzdWUgaW4gMjAxOS4gVGhpcyBpcyBub3QgbmV3IGZvciBQaGlsYWRlbHBoaWEuIENyaW1lIGluIHRoZSBjaXR5IGhhcyBiZWVuIGluY3JlYXNpbmcgZWFjaCB5ZWFyLCBidXQgd2hhdCdzIGV2ZW4gbW9yZSBzdGFnZ2VyaW5nIGlzIHRoZSB0eXBlcyBvZiBjcmltZSBwdXNoaW5nIHRoZSB0b3RhbHMgc28gaGlnaC4gVmlvbGVudCBjcmltZSBoYXMgY29uc2lzdGVudGx5IGJlZW4gb25lIG9mIHRoZSBoaWdoZXN0IGNhdGVnb3JpZXMgaW4gdGhlIHJlY2VudCBwYXN0LiBDaGVjayBvdXQgdGhpcyBbaW50ZXJhY3RpdmUgZGFzaGJvYXJkXShodHRwczovL3d3dy5hcmNnaXMuY29tL2FwcHMvZGFzaGJvYXJkcy9kOTZlNGJlNzczNzI0YzQyYjY2MTdmNzkxNWNiMGNkNikgZm9yIFBoaWxhZGVscGhpYSdzIHNob290aW5nIHZpY3RpbWl6YXRpb25zLgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmNyaW1lX2NhdHMgPC0gcGhsQ3JpbWUgJT4lCiAgbXV0YXRlKGNhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgdGV4dF9nZW5lciA9PSAiVGhlZnRzIiB+ICJUaGVmdHMiLAogICAgdGV4dF9nZW5lciA9PSAiVGhlZnQgZnJvbSBWZWhpY2xlIiB+ICJUaGVmdHMiLAogICAgdGV4dF9nZW5lciA9PSAiQWdncmF2YXRlZCBBc3NhdWx0IE5vIEZpcmVhcm0iIH4gIlZpb2xlbnQiLCAKICAgIHRleHRfZ2VuZXIgPT0gIkJ1cmdsYXJ5IFJlc2lkZW50aWFsIiB+ICJWaW9sZW50IiwKICAgIHRleHRfZ2VuZXIgPT0gIlJvYmJlcnkgTm8gRmlyZWFybSIgfiAiVmlvbGVudCIsIAogICAgdGV4dF9nZW5lciA9PSAiQnVyZ2xhcnkgTm9uLVJlc2lkZW50aWFsIiB+ICJWaW9sZW50IiwKICAgIHRleHRfZ2VuZXIgPT0gIlJvYmJlcnkgRmlyZWFybSIgfiAiVmlvbGVudCIsCiAgICB0ZXh0X2dlbmVyID09ICJSYXBlIiB+ICJSYXBlIiwKICAgIHRleHRfZ2VuZXIgPT0gIkFnZ3JhdmF0ZWQgQXNzYXVsdCBGaXJlYXJtIiB+ICJWaW9sZW50IiwKICAgIHRleHRfZ2VuZXIgPT0gIk90aGVyIEFzc2F1bHRzIiB+ICJWaW9sZW50IiwKICAgIHRleHRfZ2VuZXIgPT0gIk5hcmNvdGljIC8gRHJ1ZyBMYXcgVmlvbGF0aW9ucyIgfiAiQWxjb2hvbC9OYXJjb3RpY3MiLCAKICAgIHRleHRfZ2VuZXIgPT0gIldlYXBvbiBWaW9sYXRpb25zIiB+ICJBbGwgT3RoZXIgT2ZmZW5zZXMiLAogICAgdGV4dF9nZW5lciA9PSAiQWxsIE90aGVyIE9mZmVuc2VzIiB+ICJBbGwgT3RoZXIgT2ZmZW5zZXMiLAogICAgdGV4dF9nZW5lciA9PSAiVmFuZGFsaXNtL0NyaW1pbmFsIE1pc2NoaWVmIiB+ICJBbGwgT3RoZXIgT2ZmZW5zZXMiLAogICAgdGV4dF9nZW5lciA9PSAiRFJJVklORyBVTkRFUiBUSEUgSU5GTFVFTkNFIiB+ICJBbGNvaG9sL05hcmNvdGljcyIsCiAgICB0ZXh0X2dlbmVyID09ICJGcmF1ZCIgfiAiRmluYW5jaWFsIiwKICAgIHRleHRfZ2VuZXIgPT0gIkZvcmdlcnkgYW5kIENvdW50ZXJmZWl0aW5nIiB+ICJGaW5hbmNpYWwiLAogICAgdGV4dF9nZW5lciA9PSAiRW1iZXp6bGVtZW50IiB+ICJGaW5hbmNpYWwiLAogICAgdGV4dF9nZW5lciA9PSAiRGlzb3JkZXJseSBDb25kdWN0IiB+ICJBbGwgT3RoZXIgT2ZmZW5zZXMiLAogICAgdGV4dF9nZW5lciA9PSAiQXJzb24iIH4gIkFsbCBPdGhlciBPZmZlbnNlcyIsIAogICAgdGV4dF9nZW5lciA9PSAiT2ZmZW5zZXMgQWdhaW5zdCBGYW1pbHkgYW5kIENoaWxkcmVuIiB+ICJBbGwgT3RoZXIgT2ZmZW5zZXMiLAogICAgdGV4dF9nZW5lciA9PSAiT3RoZXIgU2V4IE9mZmVuc2VzIChOb3QgQ29tbWVyY2lhbGl6ZWQpIiB+ICJTZXgiLAogICAgdGV4dF9nZW5lciA9PSAiUHJvc3RpdHV0aW9uIGFuZCBDb21tZXJjaWFsaXplZCBWaWNlIiB+ICJTZXgiLAogICAgdGV4dF9nZW5lciA9PSAiUHVibGljIERydW5rZW5uZXNzIiB+ICJBbGNvaG9sL05hcmNvdGljcyIsCiAgICB0ZXh0X2dlbmVyID09ICJMaXF1b3IgTGF3IFZpb2xhdGlvbnMiIH4gIkFsY29ob2wvTmFyY290aWNzIiwKICAgIHRleHRfZ2VuZXIgPT0gIkdhbWJsaW5nIFZpb2xhdGlvbnMiIH4gIkFsbCBPdGhlciBPZmZlbnNlcyIsCiAgICB0ZXh0X2dlbmVyID09ICJSZWNlaXZpbmcgU3RvbGVuIFByb3BlcnR5IiB+ICJBbGwgT3RoZXIgT2ZmZW5zZXMiLAogICAgdGV4dF9nZW5lciA9PSAiVmFncmFuY3kvTG9pdGVyaW5nIiB+ICJBbGwgT3RoZXIgT2ZmZW5zZXMiLAogICAgdGV4dF9nZW5lciA9PSAiSG9taWNpZGUgLSBDcmltaW5hbCIgfiAiSG9taWNpZGUiLAogICAgdGV4dF9nZW5lciA9PSAiTW90b3IgVmVoaWNsZSBUaGVmdCIgfiAiVGhlZnRzIgogICkpCgpwaGxDcmltZV9jb3VudHMgPC0gY3JpbWVfY2F0cyAlPiUKICBncm91cF9ieShjYXRlZ29yeSkgJT4lCiAgc3VtbWFyaXplKGNvdW50PW4oKSkgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpCgpnZ3Bsb3QoZGF0YT1waGxDcmltZV9jb3VudHMsYWVzKHg9cmVvcmRlcihjYXRlZ29yeSwgLWNvdW50KSwgeT1jb3VudCkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoPTAuNSwgZmlsbCA9ICIjMGI0NjVjIikgKwogIGxhYnModGl0bGUgPSAiMjAxOSBDcmltZSBieSBPZmZlbnNlIENhdGVnb3J5Iiwgc3VidGl0bGUgPSAiUGhpbGFkZWxwaGlhIikgKwogIHBsb3RUaGVtZQpgYGAKCiMjIDIuMiBGZWF0dXJlIEVuZ2luZWVyaW5nCgpUaGUgdHlwZXMgb2YgY3JpbWUsIHNlZW4gYWJvdmUsIHdpdGggdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIG9mZmVuc2VzIHdlcmUgdmlvbGVudCBjcmltZXMgYW5kIHRoZWZ0cy4gQWNjb3JkaW5nIHRvIHRoZSByZXNlYXJjaCBieSBSZWVzIGFuZCBTY2huZXBlbCwgdGhlZnRzIGFyZSBrbm93biB0byBpbmNyZWFzZSBkdXJpbmcgTkZMIGhvbWUgZ2FtZXMuIFdoZXJlIHRoZXNlIGNyaW1lcyBvY2N1ciBob2xkIGp1c3QgYXMgbXVjaCBpbXBvcnRhbmNlIGFzIHRoZWlyIG9mZmVuc2UgY2F0ZWdvcnkuIFRoZXJlIGFyZSBtdWx0aXBsZSB3YXlzIG9mIHBvcnRyYXlpbmcgdGhpcyBkYXRhLiBBZ2dyZWdhdGluZyBjcmltaW5hbCBpbmNpZGVudHMgZnJvbSAyMDE5IHRvIGEgZmlzaG5ldCBncmlkIGdpdmVzIGFuIGlkZWEgb2Ygd2hlcmUgdGhlIG1vc3QgY3JpbWUgaXMgb2NjdXJyaW5nLCBzaW1pbGFyIHRvIHRoZSBpbnRlcmFjdGl2ZSBtYXAgYWJvdmUuIAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnBobEJvdW5kIDwtIAogIHN0X3JlYWQoImh0dHA6Ly9kYXRhLnBobC5vcGVuZGF0YS5hcmNnaXMuY29tL2RhdGFzZXRzLzA2M2Y1Zjg1ZWYxNzQ2OGViZmViYzFkMjQ5OGI3ZGFmXzAuZ2VvanNvbiIpICU+JQogIHN0X3RyYW5zZm9ybSgnRVBTRzozODU3JykKCnBobE91dGxpbmUgPC0gc3RfdW5pb24ocGhsQm91bmQpICU+JQogIHN0X3RyYW5zZm9ybSgnRVBTRzozODU3JykKCnRyYWN0cyA8LSBzdF9yZWFkKCJDZW5zdXNfVHJhY3RzXzIwMTAuZ2VvanNvbiIpICU+JQogIHN0X3RyYW5zZm9ybSgiRVBTRzozODU3IikKCnN0YWRpdW1zIDwtCiAgc3RfcmVhZCgiRGF0YS9TdGFkaXVtcy9zdGFkaXVtcy5qc29uIikgJT4lCiAgc3RfdHJhbnNmb3JtKCJFUFNHOjM4NTciKQoKbGluYyA8LSAKICBzdGFkaXVtcyAlPiUKICBmaWx0ZXIoVGVhbSA9PSAiUGhpbGFkZWxwaGlhIEVhZ2xlcyIpCgpsaW5jQnVmZmVyIDwtCiAgc3RfYnVmZmVyKGxpbmMsIDEwMDApICU+JQogIHN0X3RyYW5zZm9ybShzdF9jcnMoc3RhZGl1bXMpKQoKc2VwdGFfc3RvcHMgPC0gc3RfcmVhZCgiU0VQVEFfLV9IaWdoc3BlZWRfU3RhdGlvbnMuZ2VvanNvbiIpICU+JQogIHN0X3RyYW5zZm9ybSgiRVBTRzozODU3IikgJT4lCiAgc3RfZmlsdGVyKC4scGhsQm91bmQpCgoKc2VwdGFCdWZmZXIgPC0gCiAgICBzdF91bmlvbihzdF9idWZmZXIoc2VwdGFfc3RvcHMsIDI3NSkpICU+JQogICAgICBzdF9zZigpIAoKZmlzaG5ldEhleFBobCA8LSAKICBzdF9tYWtlX2dyaWQocGhsQm91bmQsCiAgICAgICAgICAgICAgIGNlbGxzaXplID0gNzUwLCAKICAgICAgICAgICAgICAgc3F1YXJlID0gRkFMU0UpICU+JQogIC5bcGhsQm91bmRdICU+JSAgICAgICAgICAgIAogIHN0X3NmKCkgJT4lCiAgbXV0YXRlKHVuaXF1ZUlEID0gcm93bmFtZXMoLikpCgpjcmltZV9uZXRIZXggPC0gCiAgZHBseXI6OnNlbGVjdChwaGxDcmltZSkgJT4lIAogIG11dGF0ZShjb3VudENyaW1lID0gMSkgJT4lIAogIGFnZ3JlZ2F0ZSguLCBmaXNobmV0SGV4UGhsLCBzdW0pICU+JQogIG11dGF0ZShjb3VudENyaW1lID0gcmVwbGFjZV9uYShjb3VudENyaW1lLCAwKSwKICAgICAgICAgdW5pcXVlSUQgPSByb3duYW1lcyguKSwKICAgICAgICAgY3ZJRCA9IHNhbXBsZShyb3VuZChucm93KGZpc2huZXRIZXhQaGwpIC8gMjQpLCAKICAgICAgICAgICAgICAgICAgICAgICBzaXplPW5yb3coZmlzaG5ldEhleFBobCksIHJlcGxhY2UgPSBUUlVFKSkKCmdncGxvdCgpICsKICAgIGdlb21fc2YoZGF0YSA9IGNyaW1lX25ldEhleCwgYWVzKGZpbGwgPSBjb3VudENyaW1lKSwgY29sb3IgPSAidHJhbnNwYXJlbnQiLCBzaXplID0gMCkgKwogICAgc2NhbGVfZmlsbF92aXJpZGlzKCkrCiAgICBsYWJzKHRpdGxlID0gIlRvdGFsIENvdW50IG9mIENyaW1lcyB3aXRoaW4gSGV4IEdyaWQiLAogICAgICAgIHN1YnRpdGxlID0gIlBoaWxhZGVscGhpYSwgUEEgLSAyMDE5IikgKwogIG1hcFRoZW1lCgpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpjcmltZV9qb2luZWQgPC0gbGVmdF9qb2luKHBobENyaW1lLCBlYWdsZXMsIGJ5ID0gImRhdGUiKSAlPiUKICBtdXRhdGUoaG9tZV9nYW1lID0gaWZlbHNlKHRlYW1faG9tZSA9PSAiUGhpbGFkZWxwaGlhIEVhZ2xlcyIsIDEsIDApLAogICAgICAgICBhd2F5X2dhbWUgPSBpZmVsc2UodGVhbV9hd2F5ID09ICJQaGlsYWRlbHBoaWEgRWFnbGVzIiwgMSwgMCksCiAgICAgICAgIGZhdm9yaXRlID0gaWZlbHNlKHRlYW1fZmF2b3JpdGVfaWQgPT0gIlBISSIsIDEsIDApLAogICAgICAgICByaXZhbHJ5ID0gaWZlbHNlKHRlYW1faG9tZSA9PSAiRGFsbGFzIENvd2JveXMiIHwgdGVhbV9ob21lID09ICJXYXNoaW5ndG9uIFJlZHNraW5zIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZWFtX2hvbWUgPT0gIk5ldyBZb3JrIEdpYW50cyIgfCB0ZWFtX2F3YXkgPT0gIkRhbGxhcyBDb3dib3lzIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZWFtX2F3YXkgPT0gIldhc2hpbmd0b24gUmVkc2tpbnMiIHwgdGVhbV9hd2F5ID09ICJOZXcgWW9yayBHaWFudHMiLCAxLCAwKSwKICAgICAgICAgZ2FtZWRheSA9IGlmZWxzZShzY2hlZHVsZV9wbGF5b2ZmID09ICJUUlVFIiB8IHNjaGVkdWxlX3BsYXlvZmYgPT0gIkZBTFNFIiwgMSwgMCksCiAgICAgICAgIGRvdHcgPSB3ZGF5KG1keShzY2hlZHVsZV9kYXRlKSksCiAgICAgICAgIHRvdGFsX3BvaW50cyA9IHNjb3JlX2hvbWUgKyBzY29yZV9hd2F5KQpgYGAKClBsb3R0aW5nIGNyaW1lIGFzIHBvaW50IGRhdGEsIHJlcHJlc2VudGF0aXZlIG9mIGVhY2ggaW5kaXZpZHVhbCBpbmNpZGVudCwgcHJvdmlkZXMgYSB2aXN1YWwgdW5kZXJzdGFuZGluZyB0aGF0IGRvZXMgbm90IGNhcHR1cmUgdGhlIHRydWUgYW1vdW50IG9mIGV2ZW50cyBpbiBhIGdpdmVuIGFyZWEuIFBvaW50cyBjYW4gZmFsbCBvbiB0b3Agb2YgZWFjaCBvdGhlciB3aGVuIGNyaW1lcyB0aHJvdWdob3V0IHRoZSB5ZWFyIG9jY3VyIGluIHRoZSBzYW1lIHBsYWNlLCBvciBjbG9zZSBlbm91Z2ggaW4gcHJveGltaXR5IHRvIGFwcGVhciBvbiB0aGUgc2FtZSBsb2NhdGlvbiBhdCBhIGNpdHl3aWRlIGVsZXZhdGlvbiBsaWtlIGFib3ZlLiBQbG90dGluZyB0aGUga2VybmVsIGRlbnNpdHkgb2YgY3JpbWUsIGhvd2V2ZXIsIHNob3dzIHRoZSBzYW1lIGRhdGEgd2hpbGUgb2ZmZXJpbmcgYSBiZXR0ZXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgc3BhdGlhbCBkaXN0cmlidXRpb24gb2YgdGhlc2UgaW5jaWRlbnRzLgoKU2VwYXJhdGluZyBjcmltZSBpbnRvIHRocmVlIGNhdGVnb3JpZXMgd2lsbCBiZSB0aGUgYmFzaXMgb2YgdGhlIG5leHQgY29tcG9uZW50IG9mIGFuYWx5c2lzLiBIZXJlLCBjcmltZXMgZnJvbSAyMDE5IHdpbGwgYmUgYWdncmVnYXRlZCBpbnRvIHRocmVlIHR5cGVzIG9mIGRheXM6IGRheXMgd2l0aCBubyBFYWdsZSdzIGdhbWUgKE5BKSwgZGF5cyBvbiB3aGljaCB0aGUgRWFnbGUncyBwbGF5ZWQgYXQgaG9tZSAoMSksIGFuZCBkYXlzIG9uIHdoaWNoIHRoZSBFYWdsZSdzIHBsYXllZCBhbiBhd2F5IGdhbWUgKDApLiAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhID0gY3JpbWVfam9pbmVkLCBjb2xvciA9ICIjMTY1MjY5IiwgYWxwaGEgPSAwLjI1KSArCiAgZmFjZXRfd3JhcCh+aG9tZV9nYW1lKSArIAogIGdlb21fc2YoZGF0YSA9IHBobE91dGxpbmUsIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBzaXplID0gMS4yNSkgKwogIG1hcFRoZW1lCgoKbm9fZ2FtZSA8LSBjcmltZV9qb2luZWQgJT4lCiAgZmlsdGVyKGhvbWVfZ2FtZSAhPSAxIHwgaG9tZV9nYW1lICE9IDApCgpob21lX2dhbWUgPC0gY3JpbWVfam9pbmVkICU+JQogIGZpbHRlcihob21lX2dhbWUgPT0gMSkKCmF3YXlfZ2FtZSA8LSBjcmltZV9qb2luZWQgJT4lCiAgZmlsdGVyKGhvbWVfZ2FtZSA9PSAwKQoKaG9tZV9kZW5zaXR5IDwtIAogIGdncGxvdCgpICsgCiAgZ2VvbV9zZihkYXRhID0gcGhsT3V0bGluZSwgZmlsbCA9ICJncmV5NDAiKSArCiAgc3RhdF9kZW5zaXR5MmQoZGF0YSA9IGRhdGEuZnJhbWUoc3RfY29vcmRpbmF0ZXMoaG9tZV9nYW1lKSksIAogICAgICAgICAgICAgICAgIGFlcyhYLCBZLCBmaWxsID0gLi5sZXZlbC4uLCBhbHBoYSA9IC4ubGV2ZWwuLiksCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMDEsIGJpbnMgPSA0MCwgZ2VvbSA9ICdwb2x5Z29uJykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICBzY2FsZV9hbHBoYShyYW5nZSA9IGMoMC4wMCwgMC4zNSksIGd1aWRlID0gRkFMU0UpICsKICBsYWJzKHRpdGxlID0gIkhvbWUgR2FtZXMiKSArCiAgbWFwVGhlbWUgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgphd2F5X2RlbnNpdHkgPC0gCiAgZ2dwbG90KCkgKyAKICBnZW9tX3NmKGRhdGEgPSBwaGxPdXRsaW5lLCBmaWxsID0gImdyZXk0MCIpICsKICBzdGF0X2RlbnNpdHkyZChkYXRhID0gZGF0YS5mcmFtZShzdF9jb29yZGluYXRlcyhhd2F5X2dhbWUpKSwgCiAgICAgICAgICAgICAgICAgYWVzKFgsIFksIGZpbGwgPSAuLmxldmVsLi4sIGFscGhhID0gLi5sZXZlbC4uKSwKICAgICAgICAgICAgICAgICBzaXplID0gMC4wMSwgYmlucyA9IDQwLCBnZW9tID0gJ3BvbHlnb24nKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzKCkgKwogIHNjYWxlX2FscGhhKHJhbmdlID0gYygwLjAwLCAwLjM1KSwgZ3VpZGUgPSBGQUxTRSkgKwogIGxhYnModGl0bGUgPSAiQXdheSBHYW1lcyIpICsKICBtYXBUaGVtZSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCm5vX2RlbnNpdHkgPC0gCiAgZ2dwbG90KCkgKyAKICBnZW9tX3NmKGRhdGEgPSBwaGxPdXRsaW5lLCBmaWxsID0gImdyZXk0MCIpICsKICBzdGF0X2RlbnNpdHkyZChkYXRhID0gZGF0YS5mcmFtZShzdF9jb29yZGluYXRlcyhub19nYW1lKSksIAogICAgICAgICAgICAgICAgIGFlcyhYLCBZLCBmaWxsID0gLi5sZXZlbC4uLCBhbHBoYSA9IC4ubGV2ZWwuLiksCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMDEsIGJpbnMgPSA0MCwgZ2VvbSA9ICdwb2x5Z29uJykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICBzY2FsZV9hbHBoYShyYW5nZSA9IGMoMC4wMCwgMC4zNSksIGd1aWRlID0gRkFMU0UpICsKICBsYWJzKHRpdGxlID0gIk5vIEdhbWVzIikgKwogIG1hcFRoZW1lICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ3JpZC5hcnJhbmdlKGF3YXlfZGVuc2l0eSxob21lX2RlbnNpdHksbm9fZGVuc2l0eSwgbnJvdyA9IDEpCmBgYAoKIyAzLiBHYW1lIERheSBDb3JyZWxhdGlvbnMKClNvbWUgb2YgdGhlIHJlc2VhcmNoIGluIHRoaXMgYXJlYSBoYXMgZm91bmQgdGhhdCBzcGVjaWZpYyBnYW1lIGRheSBmYWN0b3JzIGNhbiBpbmZsdWVuY2UgY3JpbWUgZHVyaW5nIE5DQUEgc3BvcnRpbmcgZXZlbnRzLiBVcHNldCB3aW5zIGFuZCBsb3NzZXMsIGZvciBpbnN0YW5jZSwgY2FuIGluZmx1ZW5jZSBjcmltaW5hbGl0eSBtb3JlIHRoYW4gYSBub3JtYWwgd2luIG9yIGxvc3MuIAoKRG8gdGhlc2UgZmFjdG9ycyBpbmZsdWVuY2UgY3JpbWUgaW4gUGhpbGFkZWxwaGlhPyAKCmBgYHtyfSAKCmNvcnJfZGF0YSA8LSByZWFkLmNzdigiRGF0YS9zcHJlYWRzcG9rZV9zY29yZXMuY3N2IikgJT4lCiAgZmlsdGVyKHRlYW1faG9tZSA9PSAiUGhpbGFkZWxwaGlhIEVhZ2xlcyIgfCB0ZWFtX2F3YXkgPT0gIlBoaWxhZGVscGhpYSBFYWdsZXMiKSAlPiUKICBmaWx0ZXIoc2NoZWR1bGVfc2Vhc29uID49IDIwMTQpICU+JQogIG11dGF0ZShkYXRlID0gbWR5KHNjaGVkdWxlX2RhdGUpKQoKY3JpbWVfMjAxOCA8LSByZWFkX3NmKCJQaGlsYWRlbHBoaWEgRWFnbGVzLzIwMTgvaW5jaWRlbnRzX3BhcnQxX3BhcnQyL2luY2lkZW50c19wYXJ0MV9wYXJ0Mi5zaHAiKSAlPiUKICBzdF90cmFuc2Zvcm0oJ0VQU0c6Mzg1NycpICU+JQogIG11dGF0ZShkYXRlID0geW1kKGRpc3BhdGNoX2QpLAogICAgICAgICBjb3VudCA9IDEpICU+JQogIGZpbHRlcihwb2ludF95ID4gMzApCgpjcmltZV8yMDE3IDwtIHJlYWRfc2YoIlBoaWxhZGVscGhpYSBFYWdsZXMvMjAxNy9pbmNpZGVudHNfcGFydDFfcGFydDIvaW5jaWRlbnRzX3BhcnQxX3BhcnQyLnNocCIpICU+JQogIHN0X3RyYW5zZm9ybSgnRVBTRzozODU3JykgJT4lCiAgbXV0YXRlKGRhdGUgPSB5bWQoZGlzcGF0Y2hfZCksCiAgICAgICAgIGNvdW50ID0gMSkgJT4lCiAgZmlsdGVyKHBvaW50X3kgPiAzMCkKCmNyaW1lXzIwMTYgPC0gcmVhZF9zZigiUGhpbGFkZWxwaGlhIEVhZ2xlcy8yMDE2L2luY2lkZW50c19wYXJ0MV9wYXJ0Mi9pbmNpZGVudHNfcGFydDFfcGFydDIuc2hwIikgJT4lCiAgc3RfdHJhbnNmb3JtKCdFUFNHOjM4NTcnKSAlPiUKICBtdXRhdGUoZGF0ZSA9IHltZChkaXNwYXRjaF9kKSwKICAgICAgICAgY291bnQgPSAxKSAlPiUKICBmaWx0ZXIocG9pbnRfeSA+IDMwKQoKY3JpbWVfMjAxNSA8LSByZWFkX3NmKCJQaGlsYWRlbHBoaWEgRWFnbGVzLzIwMTUvaW5jaWRlbnRzX3BhcnQxX3BhcnQyL2luY2lkZW50c19wYXJ0MV9wYXJ0Mi5zaHAiKSAlPiUKICBzdF90cmFuc2Zvcm0oJ0VQU0c6Mzg1NycpICU+JQogIG11dGF0ZShkYXRlID0geW1kKGRpc3BhdGNoX2QpLAogICAgICAgICBjb3VudCA9IDEpICU+JQogIGZpbHRlcihwb2ludF95ID4gMzApCgpjcmltZV8yMDE0IDwtIHJlYWRfc2YoIlBoaWxhZGVscGhpYSBFYWdsZXMvMjAxNC9pbmNpZGVudHNfcGFydDFfcGFydDIvaW5jaWRlbnRzX3BhcnQxX3BhcnQyLnNocCIpICU+JQogIHN0X3RyYW5zZm9ybSgnRVBTRzozODU3JykgJT4lCiAgbXV0YXRlKGRhdGUgPSB5bWQoZGlzcGF0Y2hfZCksCiAgICAgICAgIGNvdW50ID0gMSkgJT4lCiAgZmlsdGVyKHBvaW50X3kgPiAzMCkKCmFsbF9jcmltZSA8LSBkby5jYWxsKCJyYmluZCIsIGxpc3QocGhsQ3JpbWUsIGNyaW1lXzIwMTgsIGNyaW1lXzIwMTcsIGNyaW1lXzIwMTYsIGNyaW1lXzIwMTUsIGNyaW1lXzIwMTQpKQoKIyBFRElUIC0gZ3JvdXAgYnkgZGF0ZSBBTkQgaG91cj8gVEhJUyBET0VTTlQgSU5DTFVERSBaRVJPUyAtIHRyeSBjb21wbGV0ZSg/KQpjcmltZV9zdW1tYXJ5X2hvdXIgPC0gYWxsX2NyaW1lICU+JQogIGdyb3VwX2J5KGRhdGUsIGhvdXJfKSAlPiUKICBzdW1tYXJpemUoY3JpbWVfcGVyX2hvdXIgPSBzdW0oY291bnQpKSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkKCmNyaW1lX3N1bW1hcnlfZGF5IDwtIGFsbF9jcmltZSAlPiUKICBncm91cF9ieShkYXRlKSAlPiUKICBzdW1tYXJpemUoZGFpbHlfY3JpbWUgPSBzdW0oY291bnQpKSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkKCmNyaW1lX3N1bW1hcnlfZ2VvIDwtIGFsbF9jcmltZSAlPiUKICBncm91cF9ieShkYXRlLCBob3VyXykgJT4lCiAgc3VtbWFyaXplKGNyaW1lX3Blcl9ob3VyID0gc3VtKGNvdW50KSkKCgpmaW5hbF9wcmVwIDwtIGxlZnRfam9pbihjcmltZV9zdW1tYXJ5X2hvdXIsIGNvcnJfZGF0YSwgYnkgPSAiZGF0ZSIpICU+JQogIG11dGF0ZShob21lX2dhbWUgPSBpZmVsc2UodGVhbV9ob21lID09ICJQaGlsYWRlbHBoaWEgRWFnbGVzIiwgMSwgMCksCiAgICAgICAgIGF3YXlfZ2FtZSA9IGlmZWxzZSh0ZWFtX2F3YXkgPT0gIlBoaWxhZGVscGhpYSBFYWdsZXMiLCAxLCAwKSwKICAgICAgICAgZmF2b3JpdGUgPSBpZmVsc2UodGVhbV9mYXZvcml0ZV9pZCA9PSAiUEhJIiwgMSwgMCksCiAgICAgICAgIHJpdmFscnkgPSBpZmVsc2UodGVhbV9ob21lID09ICJEYWxsYXMgQ293Ym95cyIgfCB0ZWFtX2hvbWUgPT0gIldhc2hpbmd0b24gUmVkc2tpbnMiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlYW1faG9tZSA9PSAiTmV3IFlvcmsgR2lhbnRzIiB8IHRlYW1fYXdheSA9PSAiRGFsbGFzIENvd2JveXMiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlYW1fYXdheSA9PSAiV2FzaGluZ3RvbiBSZWRza2lucyIgfCB0ZWFtX2F3YXkgPT0gIk5ldyBZb3JrIEdpYW50cyIsIDEsIDApLAogICAgICAgICBnYW1lZGF5ID0gaWZlbHNlKHNjaGVkdWxlX3BsYXlvZmYgPT0gIlRSVUUiIHwgc2NoZWR1bGVfcGxheW9mZiA9PSAiRkFMU0UiLCAxLCAwKSwKICAgICAgICAgZG90dyA9IHdkYXkobWR5KHNjaGVkdWxlX2RhdGUpKSwKICAgICAgICAgdG90YWxfcG9pbnRzID0gc2NvcmVfaG9tZSArIHNjb3JlX2F3YXkpCgpmaW5hbCA8LSBsZWZ0X2pvaW4oZmluYWxfcHJlcCwgY3JpbWVfc3VtbWFyeV9kYXksIGJ5ID0gImRhdGUiKQpmaW5hbF9nZW8gPC0gbGVmdF9qb2luKGZpbmFsX3ByZXAsIGNyaW1lX3N1bW1hcnlfZ2VvLCBieSA9ICJkYXRlIikgJT4lCiAgc3RfYXNfc2YoKQoKZmluYWwkZGF0ZSA8LSBhcy5udW1lcmljKGZpbmFsJGRhdGUpCgpmaW5hbF9nYW1lZGF5IDwtIGZpbmFsX2dlbyAlPiUKICBmaWx0ZXIoZ2FtZWRheSA9PSAxKQoKY29yciA8LSAKICBzZWxlY3RfaWYoZmluYWwsIGlzLm51bWVyaWMpIAogIApjb3JyW2lzLm5hKGNvcnIpXSA8LSAwCgpjb3JyX2dhbWVkYXkgPC0gY29yclssIC1jKDEsMildICU+JQogIGZpbHRlcihnYW1lZGF5ID09IDEpCgpnZ2NvcnJwbG90KAogIHJvdW5kKGNvcihjb3JyX2dhbWVkYXkpLCAxKSwKICBwLm1hdCA9IGNvcl9wbWF0KGNvcnJfZ2FtZWRheSksCiAgY29sb3JzID0gYygiIzY5MTY1MiIsICJ3aGl0ZSIsICIjMTY1MjY5IiksCiAgdHlwZT0ibG93ZXIiLAogIGluc2lnID0gImJsYW5rIikgKyAgCiAgbGFicyh0aXRsZSA9ICJDb3JyZWxhdGlvbiBhY3Jvc3MgbnVtZXJpYyB2YXJpYWJsZXMiKSArCiAgcGxvdFRoZW1lCmBgYAoKVG90YWwgY3JpbWUgZG9lcyBub3Qgc2VlbSB0byBiZSBpbmZsdWVuY2VkIGJ5IGdhbWUgZGF5IGZhY3RvcnMuIFRoaXMgY291bGQgYmUgZm9yIGEgdmFyaWV0eSBvZiByZWFzb25zLiBXaGVyZWFzIHRoZSByZXNlYXJjaCB0aGF0IGRpc2NvdmVyZWQgY29ubmVjdGlvbnMgYmV0d2VlbiBpbmNyZWFzZXMgb2YgY3JpbWUgYW5kIGdhbWUgZGF5cyB3ZXJlIGNvbmR1Y3RlZCBvbiBOQ0FBIHRlYW1zIGluIHNtYWxsZXIgdG93bnMsIFBoaWxhZGVscGhpYSBpcyBvbmUgb2YgdGhlIGxhcmdlc3QgY2l0aWVzIGluIHRoZSBVbml0ZWQgU3RhdGVzIGFuZCBleHBlcmllbmNlcyBjcmltZSBpbiBhIHZlcnkgZGlmZmVyZW50IHdheSB0aGFuIGNvbGxlZ2UgdG93bnMuIAoKVGhlIGZpZ3VyZSBhYm92ZSBzdWdnZXN0cyB0aGVyZSBhcmUgbm8gc2lnbmlmaWNhbnQgY29ycmVsYXRpb25zIGJldHdlZW4gZ2FtZSBkYXlzIG9yIGdhbWUgZGF5IGZhY3RvcnMgYW5kIHRoZSBudW1iZXIgb2YgY3JpbWluYWwgaW5jaWRlbnRzIG9uIGEgZ2l2ZW4gZGF5LiBIb3dldmVyLCBpZiB0aGUgc2FtZSBwcm9jZXNzIGlzIGNvbXBsZXRlZCBmb3Igc3BlY2lmaWMgY3JpbWUgY2F0ZWdvcmllcywgd2Ugc2VlIG5vdCBtdWNoIGNoYW5nZXMuCgpgYGB7cn0KI0VESVQgLSB1c2UgY29yciBpbnN0ZWFkIG9mIGFsbCBjcmltZT8KYWxsX2NhdGVnb3JpZXMgPC0gYWxsX2NyaW1lICU+JQogIG11dGF0ZShjYXRlZ29yeSA9IGNhc2Vfd2hlbigKICAgIHRleHRfZ2VuZXIgPT0gIlRoZWZ0cyIgfiAiVGhlZnRzIiwKICAgIHRleHRfZ2VuZXIgPT0gIlRoZWZ0IGZyb20gVmVoaWNsZSIgfiAiVGhlZnRzIiwKICAgIHRleHRfZ2VuZXIgPT0gIkFnZ3JhdmF0ZWQgQXNzYXVsdCBObyBGaXJlYXJtIiB+ICJWaW9sZW50IiwgCiAgICB0ZXh0X2dlbmVyID09ICJCdXJnbGFyeSBSZXNpZGVudGlhbCIgfiAiVmlvbGVudCIsCiAgICB0ZXh0X2dlbmVyID09ICJSb2JiZXJ5IE5vIEZpcmVhcm0iIH4gIlZpb2xlbnQiLCAKICAgIHRleHRfZ2VuZXIgPT0gIkJ1cmdsYXJ5IE5vbi1SZXNpZGVudGlhbCIgfiAiVmlvbGVudCIsCiAgICB0ZXh0X2dlbmVyID09ICJSb2JiZXJ5IEZpcmVhcm0iIH4gIlZpb2xlbnQiLAogICAgdGV4dF9nZW5lciA9PSAiUmFwZSIgfiAiUmFwZSIsCiAgICB0ZXh0X2dlbmVyID09ICJBZ2dyYXZhdGVkIEFzc2F1bHQgRmlyZWFybSIgfiAiVmlvbGVudCIsCiAgICB0ZXh0X2dlbmVyID09ICJPdGhlciBBc3NhdWx0cyIgfiAiVmlvbGVudCIsCiAgICB0ZXh0X2dlbmVyID09ICJOYXJjb3RpYyAvIERydWcgTGF3IFZpb2xhdGlvbnMiIH4gIkFsY29ob2wvTmFyY290aWNzIiwgCiAgICB0ZXh0X2dlbmVyID09ICJXZWFwb24gVmlvbGF0aW9ucyIgfiAiQWxsIE90aGVyIE9mZmVuc2VzIiwKICAgIHRleHRfZ2VuZXIgPT0gIkFsbCBPdGhlciBPZmZlbnNlcyIgfiAiQWxsIE90aGVyIE9mZmVuc2VzIiwKICAgIHRleHRfZ2VuZXIgPT0gIlZhbmRhbGlzbS9DcmltaW5hbCBNaXNjaGllZiIgfiAiQWxsIE90aGVyIE9mZmVuc2VzIiwKICAgIHRleHRfZ2VuZXIgPT0gIkRSSVZJTkcgVU5ERVIgVEhFIElORkxVRU5DRSIgfiAiQWxjb2hvbC9OYXJjb3RpY3MiLAogICAgdGV4dF9nZW5lciA9PSAiRnJhdWQiIH4gIkZpbmFuY2lhbCIsCiAgICB0ZXh0X2dlbmVyID09ICJGb3JnZXJ5IGFuZCBDb3VudGVyZmVpdGluZyIgfiAiRmluYW5jaWFsIiwKICAgIHRleHRfZ2VuZXIgPT0gIkVtYmV6emxlbWVudCIgfiAiRmluYW5jaWFsIiwKICAgIHRleHRfZ2VuZXIgPT0gIkRpc29yZGVybHkgQ29uZHVjdCIgfiAiQWxsIE90aGVyIE9mZmVuc2VzIiwKICAgIHRleHRfZ2VuZXIgPT0gIkFyc29uIiB+ICJBbGwgT3RoZXIgT2ZmZW5zZXMiLCAKICAgIHRleHRfZ2VuZXIgPT0gIk9mZmVuc2VzIEFnYWluc3QgRmFtaWx5IGFuZCBDaGlsZHJlbiIgfiAiQWxsIE90aGVyIE9mZmVuc2VzIiwKICAgIHRleHRfZ2VuZXIgPT0gIk90aGVyIFNleCBPZmZlbnNlcyAoTm90IENvbW1lcmNpYWxpemVkKSIgfiAiU2V4IiwKICAgIHRleHRfZ2VuZXIgPT0gIlByb3N0aXR1dGlvbiBhbmQgQ29tbWVyY2lhbGl6ZWQgVmljZSIgfiAiU2V4IiwKICAgIHRleHRfZ2VuZXIgPT0gIlB1YmxpYyBEcnVua2VubmVzcyIgfiAiQWxjb2hvbC9OYXJjb3RpY3MiLAogICAgdGV4dF9nZW5lciA9PSAiTGlxdW9yIExhdyBWaW9sYXRpb25zIiB+ICJBbGNvaG9sL05hcmNvdGljcyIsCiAgICB0ZXh0X2dlbmVyID09ICJHYW1ibGluZyBWaW9sYXRpb25zIiB+ICJBbGwgT3RoZXIgT2ZmZW5zZXMiLAogICAgdGV4dF9nZW5lciA9PSAiUmVjZWl2aW5nIFN0b2xlbiBQcm9wZXJ0eSIgfiAiQWxsIE90aGVyIE9mZmVuc2VzIiwKICAgIHRleHRfZ2VuZXIgPT0gIlZhZ3JhbmN5L0xvaXRlcmluZyIgfiAiQWxsIE90aGVyIE9mZmVuc2VzIiwKICAgIHRleHRfZ2VuZXIgPT0gIkhvbWljaWRlIC0gQ3JpbWluYWwiIH4gIkhvbWljaWRlIiwKICAgIHRleHRfZ2VuZXIgPT0gIk1vdG9yIFZlaGljbGUgVGhlZnQiIH4gIlRoZWZ0cyIKICApKQoKYGBgCgoKYGBge3J9CnZpb2xlbnRfY3JpbWVzIDwtIGFsbF9jYXRlZ29yaWVzICU+JQogIGZpbHRlcihjYXRlZ29yeSA9PSAiVmlvbGVudCIpCgpzdW1tYXJ5X3Zpb2xlbnQgPC0gdmlvbGVudF9jcmltZXMgJT4lCiAgZ3JvdXBfYnkoZGF0ZSkgJT4lCiAgc3VtbWFyaXplKGNyaW1lX2NvdW50ID0gc3VtKGNvdW50KSkgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpCgpmaW5hbF92aW9sZW50IDwtIGxlZnRfam9pbihzdW1tYXJ5X3Zpb2xlbnQsIGNvcnJfZGF0YSwgYnkgPSAiZGF0ZSIpICU+JQogIG11dGF0ZShob21lX2dhbWUgPSBpZmVsc2UodGVhbV9ob21lID09ICJQaGlsYWRlbHBoaWEgRWFnbGVzIiwgMSwgMCksCiAgICAgICAgIGF3YXlfZ2FtZSA9IGlmZWxzZSh0ZWFtX2F3YXkgPT0gIlBoaWxhZGVscGhpYSBFYWdsZXMiLCAxLCAwKSwKICAgICAgICAgZmF2b3JpdGUgPSBpZmVsc2UodGVhbV9mYXZvcml0ZV9pZCA9PSAiUEhJIiwgMSwgMCksCiAgICAgICAgIHJpdmFscnkgPSBpZmVsc2UodGVhbV9ob21lID09ICJEYWxsYXMgQ293Ym95cyIgfCB0ZWFtX2hvbWUgPT0gIldhc2hpbmd0b24gUmVkc2tpbnMiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlYW1faG9tZSA9PSAiTmV3IFlvcmsgR2lhbnRzIiB8IHRlYW1fYXdheSA9PSAiRGFsbGFzIENvd2JveXMiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlYW1fYXdheSA9PSAiV2FzaGluZ3RvbiBSZWRza2lucyIgfCB0ZWFtX2F3YXkgPT0gIk5ldyBZb3JrIEdpYW50cyIsIDEsIDApLAogICAgICAgICBnYW1lZGF5ID0gaWZlbHNlKHNjaGVkdWxlX3BsYXlvZmYgPT0gIlRSVUUiIHwgc2NoZWR1bGVfcGxheW9mZiA9PSAiRkFMU0UiLCAxLCAwKSwKICAgICAgICAgZG90dyA9IHdkYXkobWR5KHNjaGVkdWxlX2RhdGUpKSwKICAgICAgICAgdG90YWxfcG9pbnRzID0gc2NvcmVfaG9tZSArIHNjb3JlX2F3YXkpCgpjb3JyX3Zpb2xlbnQgPC0gCiAgc2VsZWN0X2lmKGZpbmFsX3Zpb2xlbnQsIGlzLm51bWVyaWMpCgpjb3JyX3Zpb2xlbnRbaXMubmEoY29ycl92aW9sZW50KV0gPC0gMAoKY29ycl92aW9sZW50ICU+JQogIGZpbHRlcihnYW1lZGF5ID09IDEpCgpnZ2NvcnJwbG90KAogIHJvdW5kKGNvcihjb3JyX3Zpb2xlbnQpLCAxKSwgCiAgcC5tYXQgPSBjb3JfcG1hdChjb3JyX3Zpb2xlbnQpLAogIGNvbG9ycyA9IGMoIiM2OTE2NTIiLCAid2hpdGUiLCAiIzE2NTI2OSIpLAogIHR5cGU9Imxvd2VyIiwKICBpbnNpZyA9ICJibGFuayIpICsgIAogIGxhYnModGl0bGUgPSAiVmlvbGVudCBDcmltZXMiKSArCiAgcGxvdFRoZW1lCgojIEFMQ09IT0wKCmFsY19uYXJjX2NyaW1lcyA8LSBhbGxfY2F0ZWdvcmllcyAlPiUKICBmaWx0ZXIoY2F0ZWdvcnkgPT0gIkFsY29ob2wvTmFyY290aWNzIikKCnN1bW1hcnlfYWxjIDwtIGFsY19uYXJjX2NyaW1lcyAlPiUKICBncm91cF9ieShkYXRlKSAlPiUKICBzdW1tYXJpemUoY3JpbWVfY291bnQgPSBzdW0oY291bnQpKSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkKCmZpbmFsX2FsYyA8LSBsZWZ0X2pvaW4oc3VtbWFyeV9hbGMsIGNvcnJfZGF0YSwgYnkgPSAiZGF0ZSIpICU+JQogIG11dGF0ZShob21lX2dhbWUgPSBpZmVsc2UodGVhbV9ob21lID09ICJQaGlsYWRlbHBoaWEgRWFnbGVzIiwgMSwgMCksCiAgICAgICAgIGF3YXlfZ2FtZSA9IGlmZWxzZSh0ZWFtX2F3YXkgPT0gIlBoaWxhZGVscGhpYSBFYWdsZXMiLCAxLCAwKSwKICAgICAgICAgZmF2b3JpdGUgPSBpZmVsc2UodGVhbV9mYXZvcml0ZV9pZCA9PSAiUEhJIiwgMSwgMCksCiAgICAgICAgIHJpdmFscnkgPSBpZmVsc2UodGVhbV9ob21lID09ICJEYWxsYXMgQ293Ym95cyIgfCB0ZWFtX2hvbWUgPT0gIldhc2hpbmd0b24gUmVkc2tpbnMiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlYW1faG9tZSA9PSAiTmV3IFlvcmsgR2lhbnRzIiB8IHRlYW1fYXdheSA9PSAiRGFsbGFzIENvd2JveXMiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlYW1fYXdheSA9PSAiV2FzaGluZ3RvbiBSZWRza2lucyIgfCB0ZWFtX2F3YXkgPT0gIk5ldyBZb3JrIEdpYW50cyIsIDEsIDApLAogICAgICAgICBnYW1lZGF5ID0gaWZlbHNlKHNjaGVkdWxlX3BsYXlvZmYgPT0gIlRSVUUiIHwgc2NoZWR1bGVfcGxheW9mZiA9PSAiRkFMU0UiLCAxLCAwKSwKICAgICAgICAgZG90dyA9IHdkYXkobWR5KHNjaGVkdWxlX2RhdGUpKSwKICAgICAgICAgdG90YWxfcG9pbnRzID0gc2NvcmVfaG9tZSArIHNjb3JlX2F3YXkpIAoKCmNvcnJfYWxjIDwtIAogIHNlbGVjdF9pZihmaW5hbF9hbGMsIGlzLm51bWVyaWMpCgpjb3JyX2FsY1tpcy5uYShjb3JyX2FsYyldIDwtIDAKCmNvcnJfYWxjICU+JQogIGZpbHRlcihnYW1lZGF5ID09IDEpCgpnZ2NvcnJwbG90KAogIHJvdW5kKGNvcihjb3JyX2FsYyksIDEpLCAKICBwLm1hdCA9IGNvcl9wbWF0KGNvcnJfYWxjKSwKICBjb2xvcnMgPSBjKCIjNjkxNjUyIiwgIndoaXRlIiwgIiMxNjUyNjkiKSwKICB0eXBlPSJsb3dlciIsCiAgaW5zaWcgPSAiYmxhbmsiKSArICAKICBsYWJzKHRpdGxlID0gIkFsY29ob2wvTmFyY290aWNzIikgKwogIHBsb3RUaGVtZQoKIyBUSEVGVFMKCnRoZWZ0X2NyaW1lcyA8LSBhbGxfY2F0ZWdvcmllcyAlPiUKICBmaWx0ZXIoY2F0ZWdvcnkgPT0gIlRoZWZ0cyIpCgpzdW1tYXJ5X3RoZWZ0IDwtIHRoZWZ0X2NyaW1lcyAlPiUKICBncm91cF9ieShkYXRlKSAlPiUKICBzdW1tYXJpemUoY3JpbWVfY291bnQgPSBzdW0oY291bnQpKSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkKCmZpbmFsX3RoZWZ0IDwtIGxlZnRfam9pbihzdW1tYXJ5X3RoZWZ0LCBjb3JyX2RhdGEsIGJ5ID0gImRhdGUiKSAlPiUKICBtdXRhdGUoaG9tZV9nYW1lID0gaWZlbHNlKHRlYW1faG9tZSA9PSAiUGhpbGFkZWxwaGlhIEVhZ2xlcyIsIDEsIDApLAogICAgICAgICBhd2F5X2dhbWUgPSBpZmVsc2UodGVhbV9hd2F5ID09ICJQaGlsYWRlbHBoaWEgRWFnbGVzIiwgMSwgMCksCiAgICAgICAgIGZhdm9yaXRlID0gaWZlbHNlKHRlYW1fZmF2b3JpdGVfaWQgPT0gIlBISSIsIDEsIDApLAogICAgICAgICByaXZhbHJ5ID0gaWZlbHNlKHRlYW1faG9tZSA9PSAiRGFsbGFzIENvd2JveXMiIHwgdGVhbV9ob21lID09ICJXYXNoaW5ndG9uIFJlZHNraW5zIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZWFtX2hvbWUgPT0gIk5ldyBZb3JrIEdpYW50cyIgfCB0ZWFtX2F3YXkgPT0gIkRhbGxhcyBDb3dib3lzIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZWFtX2F3YXkgPT0gIldhc2hpbmd0b24gUmVkc2tpbnMiIHwgdGVhbV9hd2F5ID09ICJOZXcgWW9yayBHaWFudHMiLCAxLCAwKSwKICAgICAgICAgZ2FtZWRheSA9IGlmZWxzZShzY2hlZHVsZV9wbGF5b2ZmID09ICJUUlVFIiB8IHNjaGVkdWxlX3BsYXlvZmYgPT0gIkZBTFNFIiwgMSwgMCksCiAgICAgICAgIGRvdHcgPSB3ZGF5KG1keShzY2hlZHVsZV9kYXRlKSksCiAgICAgICAgIHRvdGFsX3BvaW50cyA9IHNjb3JlX2hvbWUgKyBzY29yZV9hd2F5KSAKCmNvcnJfdGhlZnQgPC0gCiAgc2VsZWN0X2lmKGZpbmFsX3RoZWZ0LCBpcy5udW1lcmljKQoKY29ycl90aGVmdFtpcy5uYShjb3JyX3RoZWZ0KV0gPC0gMAoKY29ycl90aGVmdCAlPiUKICBmaWx0ZXIoZ2FtZWRheSA9PSAxKQoKZ2djb3JycGxvdCgKICByb3VuZChjb3IoY29ycl90aGVmdCksIDEpLCAKICBwLm1hdCA9IGNvcl9wbWF0KGNvcnJfdGhlZnQpLAogIGNvbG9ycyA9IGMoIiM2OTE2NTIiLCAid2hpdGUiLCAiIzE2NTI2OSIpLAogIHR5cGU9Imxvd2VyIiwKICBpbnNpZyA9ICJibGFuayIpICsgIAogIGxhYnModGl0bGUgPSAiVGhlZnRzIikgKwogIHBsb3RUaGVtZQpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQojIGdnYXJyYW5nZSh2aW9sZW50X3Bsb3QsIHRoZWZ0X3Bsb3QsIGFsY19wbG90LCAKIyAgICAgICAgICAgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIAojICAgICAgICAgICBucm93ID0gMSwKIyAgICAgICAgICAgcnJlbW92ZSgiYXhpcyIpKQpgYGAKCiMgNC4gVGVtcG9yYWwgQW5hbHlzaXMKClNpbmNlICBnYW1lIGRheSBhdHRyaWJ1dGVzIGRvIG5vdCBzZWVtIHRvIGJlIHNpZ25pZmljYW50LCB0aW1lIGlzIGFuYWx5emVkIG5leHQuCgpgYGB7cn0KYWxsX3RpbWUgPC0gbGVmdF9qb2luKGFsbF9jYXRlZ29yaWVzLCBjb3JyX2RhdGEsIGJ5ID0gImRhdGUiKSAlPiUKICBtdXRhdGUoaG9tZV9nYW1lID0gaWZlbHNlKHRlYW1faG9tZSA9PSAiUGhpbGFkZWxwaGlhIEVhZ2xlcyIsIDEsIDApLAogICAgICAgICBhd2F5X2dhbWUgPSBpZmVsc2UodGVhbV9hd2F5ID09ICJQaGlsYWRlbHBoaWEgRWFnbGVzIiwgMSwgMCksCiAgICAgICAgIGZhdm9yaXRlID0gaWZlbHNlKHRlYW1fZmF2b3JpdGVfaWQgPT0gIlBISSIsIDEsIDApLAogICAgICAgICByaXZhbHJ5ID0gaWZlbHNlKHRlYW1faG9tZSA9PSAiRGFsbGFzIENvd2JveXMiIHwgdGVhbV9ob21lID09ICJXYXNoaW5ndG9uIFJlZHNraW5zIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZWFtX2hvbWUgPT0gIk5ldyBZb3JrIEdpYW50cyIgfCB0ZWFtX2F3YXkgPT0gIkRhbGxhcyBDb3dib3lzIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZWFtX2F3YXkgPT0gIldhc2hpbmd0b24gUmVkc2tpbnMiIHwgdGVhbV9hd2F5ID09ICJOZXcgWW9yayBHaWFudHMiLCAxLCAwKSwKICAgICAgICAgZ2FtZWRheSA9IGlmZWxzZShzY2hlZHVsZV9wbGF5b2ZmID09ICJUUlVFIiB8IHNjaGVkdWxlX3BsYXlvZmYgPT0gIkZBTFNFIiwgMSwgMCksCiAgICAgICAgIGRvdHcgPSB3ZGF5KG1keShzY2hlZHVsZV9kYXRlKSksCiAgICAgICAgIHRvdGFsX3BvaW50cyA9IHNjb3JlX2hvbWUgKyBzY29yZV9hd2F5KSAKCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShzY2FsZXMpCgphbGxfdGltZSAlPiUKICBncm91cF9ieShjYXRlZ29yeSwgaG91cl8pICU+JQogIHN1bW1hcmlzZShjb3VudD1uKCkpICU+JQogIGdncGxvdChhZXMoeD1jYXRlZ29yeSwgeT1ob3VyXykpICsKICBnZW9tX3RpbGUoYWVzKGZpbGw9Y291bnQpKSArCiAgbGFicyh4PSJDcmltZSBUeXBlIiwgeSA9ICJIb3VyICgwLTIzKSIsIHRpdGxlPSIyMDE0LTIwMTkgVG90YWwiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoIk51bWJlciBvZiBDcmltZXMiLGxhYmVsPWNvbW1hKSArCiAgY29vcmRfZmxpcCgpCgphbGxfdGltZSAlPiUKICBmaWx0ZXIoZ2FtZWRheSA9PSAxKSAlPiUKICBncm91cF9ieShjYXRlZ29yeSxob3VyXykgJT4lCiAgc3VtbWFyaXNlKGNvdW50PW4oKSkgJT4lCiAgZ2dwbG90KGFlcyh4PWNhdGVnb3J5LCB5PWhvdXJfKSkgKwogIGdlb21fdGlsZShhZXMoZmlsbD1jb3VudCkpICsKICBsYWJzKHg9IkNyaW1lIFR5cGUiLCB5ID0gIkhvdXIgKDAtMjMpIiwgdGl0bGU9IjIwMTQtMjAxOSBHYW1lZGF5cyIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYygiTnVtYmVyIG9mIENyaW1lcyIsbGFiZWw9Y29tbWEpICsgCiAgY29vcmRfZmxpcCgpCmBgYAoKYGBge3J9CmNyaW1lX3Rlc3QgPC0gY3JpbWVfam9pbmVkICU+JQogIGdyb3VwX2J5KGRhdGUsIGdhbWVkYXksIGhvdXJfKSAlPiUKICBzdW1tYXJpemUoY3JpbWVzX3Blcl9ob3VyID0gc3VtKGNvdW50KSkgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpCgp0ZXN0X2F2ZXJhZ2VzIDwtIGNyaW1lX3Rlc3QgJT4lCiAgZ3JvdXBfYnkoaG91cl8sIGdhbWVkYXkpICU+JQogIHN1bW1hcml6ZShhdmdfcGVyX2hvdXIgPSBtZWFuKGNyaW1lc19wZXJfaG91cikpCgp0ZXN0X2F2ZXJhZ2VzIDwtIHRlc3RfYXZlcmFnZXNbLTQ5LF0KICAKdGVzdF9hdmVyYWdlc1tpcy5uYSh0ZXN0X2F2ZXJhZ2VzKV0gPC0gMAoKCmdncGxvdCh0ZXN0X2F2ZXJhZ2VzLCBhZXMoeCA9IGhvdXJfLCB5ID0gYXZnX3Blcl9ob3VyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZmFjZXRfd3JhcCh+Z2FtZWRheSkgKwogIHBsb3RUaGVtZQogIApgYGAKClRoZSBmaWd1cmUgYWJvdmUgc3VnZ2VzdHMgb3Zlcm5pZ2h0IGNyaW1lcyBhcmUgYSBiaXQgbW9yZSBjb21tb24gKG9uIGF2ZXJhZ2UpIG9uIGRheXMgd2l0aCBlYWdsZXMgZ2FtZXMuIAoKIyA1LiBHZW9zcGF0aWFsIEFuYWx5c2lzCgojIyA1LjEgTGluY29sbiBGaW5hbmNpYWwgRmllbGQKCldlIGFscmVhZHkga25vdyB3aHkgY3JpbWUgd291bGQgYmUgbGlrZWx5IHRvIG9jY3VyIGFyb3VuZCBhIHN0YWRpdW0sIGJ1dCBoZXJlIHdlIHdpbGwgc2VlIGhvdyB0aGUgTGluYyBzcGVjaWZpY2FsbHkgcmVsYXRlcyB0byBjcmltZSBvbiBnYW1lIGRheXMuCgpgYGB7cn0KCiMgYXZnIGNyaW1lIHBlciBob3VyIG9uIGdhbWVkYXlzIHdpdGhpbiBidWZmZXIgdnMgYXZnIGNyaW1lIHBlciBob3VyIHdpdGhpbiBidWZmZXIgb24gb3RoZXIgZGF5cwoKbGluY19qb2luZWQgPC0gc3Rfam9pbihsaW5jQnVmZmVyLCBhbGxfY2F0ZWdvcmllcywgam9pbiA9IHN0X2ludGVyc2VjdHMpCgpsaW5jX2dyb3VwIDwtIGxlZnRfam9pbihsaW5jX2pvaW5lZCwgY29ycl9kYXRhLCBieSA9ICJkYXRlIikgJT4lCiAgbXV0YXRlKGhvbWVfZ2FtZSA9IGlmZWxzZSh0ZWFtX2hvbWUgPT0gIlBoaWxhZGVscGhpYSBFYWdsZXMiLCAxLCAwKSwKICAgICAgICAgYXdheV9nYW1lID0gaWZlbHNlKHRlYW1fYXdheSA9PSAiUGhpbGFkZWxwaGlhIEVhZ2xlcyIsIDEsIDApLAogICAgICAgICBmYXZvcml0ZSA9IGlmZWxzZSh0ZWFtX2Zhdm9yaXRlX2lkID09ICJQSEkiLCAxLCAwKSwKICAgICAgICAgcml2YWxyeSA9IGlmZWxzZSh0ZWFtX2hvbWUgPT0gIkRhbGxhcyBDb3dib3lzIiB8IHRlYW1faG9tZSA9PSAiV2FzaGluZ3RvbiBSZWRza2lucyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVhbV9ob21lID09ICJOZXcgWW9yayBHaWFudHMiIHwgdGVhbV9hd2F5ID09ICJEYWxsYXMgQ293Ym95cyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVhbV9hd2F5ID09ICJXYXNoaW5ndG9uIFJlZHNraW5zIiB8IHRlYW1fYXdheSA9PSAiTmV3IFlvcmsgR2lhbnRzIiwgMSwgMCksCiAgICAgICAgIGdhbWVkYXkgPSBpZmVsc2Uoc2NoZWR1bGVfcGxheW9mZiA9PSAiVFJVRSIgfCBzY2hlZHVsZV9wbGF5b2ZmID09ICJGQUxTRSIsIDEsIDApLAogICAgICAgICBkb3R3ID0gd2RheShtZHkoc2NoZWR1bGVfZGF0ZSkpLAogICAgICAgICB0b3RhbF9wb2ludHMgPSBzY29yZV9ob21lICsgc2NvcmVfYXdheSkKCiMgU0VQQVJBVEUgQlkgR0FNRURBWSBGSVJTVCAtIGZhY2V0IHdyYXAgd2lsbCB1c2Ugc2FtZSBzY2FsZS4KCmxpbmNfZ3JvdXAyIDwtIGxpbmNfZ3JvdXAgJT4lCiAgbXV0YXRlKHllYXIgPSB5ZWFyKHltZChkYXRlKSkpCgpsaW5jX3ByZXAgPC0gbGluY19ncm91cCAlPiUKICBncm91cF9ieShkYXRlLCBnYW1lZGF5LCBob3VyXykgJT4lCiAgc3VtbWFyaXplKGNyaW1lc19wZXJfaG91ciA9IHN1bShjb3VudCkpICU+JQogIHN0X2Ryb3BfZ2VvbWV0cnkoKQoKbGluY19hdmVyYWdlcyA8LSBsaW5jX3ByZXAgJT4lCiAgZ3JvdXBfYnkoaG91cl8sIGdhbWVkYXkpICU+JQogIHN1bW1hcml6ZShhdmdfcGVyX2hvdXIgPSBtZWFuKGNyaW1lc19wZXJfaG91cikpCgojIHRlc3RfYXZlcmFnZXMgPC0gdGVzdF9hdmVyYWdlc1stNDksXQogIApsaW5jX2F2ZXJhZ2VzW2lzLm5hKGxpbmNfYXZlcmFnZXMpXSA8LSAwCgpsaW5jX3RhYmxlIDwtIGxpbmNfYXZlcmFnZXMgJT4lCiAgZ3JvdXBfYnkoZ2FtZWRheSkgJT4lCiAgc3VtbWFyaXplKHBlcl9ob3VyX2F2ZyA9IG1lYW4oYXZnX3Blcl9ob3VyKSkKCiMgRFQ6OmRhdGF0YWJsZShsaW5jX3RhYmxlLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSxzY3JvbGxYPSc0MDBweCcpKQprYWJsZShsaW5jX3RhYmxlLCAic2ltcGxlIikKYGBgCgpUaGUgdGFibGUgYWJvdmUgc2hvd3MgdGhhdCB3aXRoaW4gMTAwMCBtZXRlcnMgb2YgTGluY29sbiBGaW5hbmNpYWwgRmllbGQsIHRoZSBhdmVyYWdlIG51bWJlciBvZiBjcmltZXMgY29tbWl0dGVkIGVhY2ggaG91ciBpcyBzbGlnaHRseSBoaWdoZXIgb24gZ2FtZSBkYXlzLiBUaGUgYXZlcmFnZSBjaXR5IGJsb2NrIGluIFBoaWxhZGVscGhpYSBpcyBhYm91dCA0MDAtNTAwIGZlZXQuIFRoaXMgbWVhbnMgb3VyIGJ1ZmZlciBpcyBhcm91bmQgNyBvciA4IGJsb2NrcyBhcm91bmQgdGhlIExpbmMuIFRoaXMgaXMgYW4gaW50ZXJlc3RpbmcgcmVzdWx0IGFzIExpbmNvbG4gRmluYW5jaWFsIEZpZWxkLCBhcyB3ZWxsIGFzIFBoaWxhZGVscGhpYSdzIG90aGVyIHByb2Zlc3Npb25hbCBzcG9ydHMgc3RhZGl1bXMgKFdlbGxzIEZhcmdvIENlbnRlciBhbmQgQ2l0aXplbnMgQmFuayBQYXJrKSwgYXJlIGluIHRoZWlyIG93biBwYXJ0IG9mIHRoZSBjaXR5LiBUaGlzIHNtYWxsIG9mIGFuIGluY3JlYXNlLCBuZWFybHkgMS4yIHRvIDEuMyBjcmltZXMgcGVyIGhvdXIsIGlzIG9uY2UgYWdhaW4gbm90IGNvbnNpc3RlbnQgd2l0aCBwcmV2aW91cyByZXNlYXJjaC4gCgpMZXQncyBzZWUgaWYgcmVwZWF0aW5nIHRoaXMgcHJvY2VzcyBmb3Igb3VyIHRocmVlIG9mZmVuc2UgY2F0ZWdvcmllcyBzaG93IGFueSBpbnRlcmVzdGluZyByZXN1bHRzLiAKCipOb3RlOiBUaGUgZm9sbG93aW5nIGxpbmUgZ3JhcGhzIGRvIG5vdCBpbmNsdWRlIHplcm8gdmFsdWVzKgoKYGBge3IsIGNhY2hlPVRSVUV9CmxpbmNfY2F0X3ByZXAgPC0gbGluY19ncm91cCAlPiUKICBncm91cF9ieShkYXRlLCBnYW1lZGF5LCBjYXRlZ29yeSwgaG91cl8pICU+JQogIHN1bW1hcml6ZShjcmltZXNfcGVyX2hvdXIgPSBzdW0oY291bnQpKSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkKCmxpbmNfY2F0X2F2ZXJhZ2VzIDwtIGxpbmNfY2F0X3ByZXAgJT4lCiAgZ3JvdXBfYnkoaG91cl8sIGdhbWVkYXksIGNhdGVnb3J5KSAlPiUKICBzdW1tYXJpemUoYXZnX3Blcl9ob3VyID0gbWVhbihjcmltZXNfcGVyX2hvdXIpKQoKbGluY19jYXRfYXZlcmFnZXNbaXMubmEobGluY19jYXRfYXZlcmFnZXMpXSA8LSAwCgpsaW5jX2NhdF90YWJsZSA8LSBsaW5jX2NhdF9hdmVyYWdlcyAlPiUKICBncm91cF9ieShnYW1lZGF5LGNhdGVnb3J5KSAlPiUKICBzdW1tYXJpemUocGVyX2hvdXJfYXZnID0gbWVhbihhdmdfcGVyX2hvdXIpKQoKZ2dwbG90KGxpbmNfY2F0X3RhYmxlLCAKICAgICAgIGFlcyh4ID0gcmVvcmRlcihjYXRlZ29yeSwgLXBlcl9ob3VyX2F2ZyksCiAgICAgICAgICAgeSA9IHBlcl9ob3VyX2F2ZywKICAgICAgICAgICBjb2xvciA9IGFzLmZhY3RvcihnYW1lZGF5KSwKICAgICAgICAgICBncm91cCA9IGFzLmZhY3RvcihnYW1lZGF5KSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsKICBwbG90VGhlbWUgKwogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBDcmltZXMgUGVyIEhvdXIgV2l0aGluIDEwMDAgbS4gb2YgTGluY29sbiBGaW5hbmNpYWwgRmllbGQiKSsKICBwbG90VGhlbWUKYGBgCgoKYGBge3IsIGNhY2hlPVRSVUV9CmxpbmNfY2F0X3ByZXAgPC0gbGluY19ncm91cDIgJT4lCiAgZ3JvdXBfYnkoZGF0ZSwgeWVhciwgZ2FtZWRheSwgY2F0ZWdvcnksIGhvdXJfKSAlPiUKICBzdW1tYXJpemUoY3JpbWVzX3Blcl9ob3VyID0gc3VtKGNvdW50KSkgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpCgpsaW5jX2NhdF9hdmVyYWdlcyA8LSBsaW5jX2NhdF9wcmVwICU+JQogIGdyb3VwX2J5KHllYXIsIGhvdXJfLCBnYW1lZGF5LCBjYXRlZ29yeSkgJT4lCiAgc3VtbWFyaXplKGF2Z19wZXJfaG91ciA9IG1lYW4oY3JpbWVzX3Blcl9ob3VyKSkKCmxpbmNfY2F0X2F2ZXJhZ2VzW2lzLm5hKGxpbmNfY2F0X2F2ZXJhZ2VzKV0gPC0gMAoKbGluY19jYXRfdGFibGUgPC0gbGluY19jYXRfYXZlcmFnZXMgJT4lCiAgZ3JvdXBfYnkoeWVhcixnYW1lZGF5LGNhdGVnb3J5KSAlPiUKICBzdW1tYXJpemUocGVyX2hvdXJfYXZnID0gbWVhbihhdmdfcGVyX2hvdXIpKQoKZ2dwbG90KGxpbmNfY2F0X3RhYmxlLCAKICAgICAgIGFlcyh4ID0gcmVvcmRlcihjYXRlZ29yeSwgLXBlcl9ob3VyX2F2ZyksCiAgICAgICAgICAgeSA9IHBlcl9ob3VyX2F2ZywKICAgICAgICAgICBjb2xvciA9IGFzLmZhY3RvcihnYW1lZGF5KSwKICAgICAgICAgICBncm91cCA9IGFzLmZhY3RvcihnYW1lZGF5KSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsKICBwbG90VGhlbWUgKwogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBDcmltZXMgUGVyIEhvdXIgV2l0aGluIDEwMDAgbS4gb2YgTGluY29sbiBGaW5hbmNpYWwgRmllbGQiLAogICAgICAgc3VidGl0bGUgPSAiQnkgWWVhciIpKwogIGZhY2V0X3dyYXAofnllYXIsIHNjYWxlcyA9ICJmcmVlIikrCiAgcGxvdFRoZW1lCmBgYAoKCiMjIDUuMiBCYXJzCgpMZXQncyBzZWUgaWYgYXZlcmFnZSBjcmltZXMgcGVyIGhvdXIgY2hhbmdlcyB3aXRoaW4gMiBibG9ja3Mgb2YgUGhpbGx5IGJhcnMgYW5kIHB1YnMuIAoKYGBge3J9CmJhcnMgPC0gc3RfcmVhZCgiZGF0YS9wdWJfcG9pbnQuZ2VvanNvbiIpICU+JQogIHN0X3RyYW5zZm9ybSgiRVBTRzozODU3IikgJT4lCiAgc3RfYXNfc2YoKQoKYmFyX2J1ZmZlciA8LQogIHN0X2J1ZmZlcihiYXJzLCAyNzUpICU+JQogIHN0X3VuaW9uKCkgJT4lCiAgc3RfYXNfc2YoKQoKYmFyc19qb2luZWQgPC0gc3Rfam9pbihiYXJfYnVmZmVyLCBhbGxfY2F0ZWdvcmllcywgam9pbiA9IHN0X2ludGVyc2VjdHMpCgpiYXJfZ3JvdXAgPC0gbGVmdF9qb2luKGJhcnNfam9pbmVkLCBjb3JyX2RhdGEsIGJ5ID0gImRhdGUiKSAlPiUKICBtdXRhdGUoaG9tZV9nYW1lID0gaWZlbHNlKHRlYW1faG9tZSA9PSAiUGhpbGFkZWxwaGlhIEVhZ2xlcyIsIDEsIDApLAogICAgICAgICBhd2F5X2dhbWUgPSBpZmVsc2UodGVhbV9hd2F5ID09ICJQaGlsYWRlbHBoaWEgRWFnbGVzIiwgMSwgMCksCiAgICAgICAgIGZhdm9yaXRlID0gaWZlbHNlKHRlYW1fZmF2b3JpdGVfaWQgPT0gIlBISSIsIDEsIDApLAogICAgICAgICByaXZhbHJ5ID0gaWZlbHNlKHRlYW1faG9tZSA9PSAiRGFsbGFzIENvd2JveXMiIHwgdGVhbV9ob21lID09ICJXYXNoaW5ndG9uIFJlZHNraW5zIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZWFtX2hvbWUgPT0gIk5ldyBZb3JrIEdpYW50cyIgfCB0ZWFtX2F3YXkgPT0gIkRhbGxhcyBDb3dib3lzIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZWFtX2F3YXkgPT0gIldhc2hpbmd0b24gUmVkc2tpbnMiIHwgdGVhbV9hd2F5ID09ICJOZXcgWW9yayBHaWFudHMiLCAxLCAwKSwKICAgICAgICAgZ2FtZWRheSA9IGlmZWxzZShzY2hlZHVsZV9wbGF5b2ZmID09ICJUUlVFIiB8IHNjaGVkdWxlX3BsYXlvZmYgPT0gIkZBTFNFIiwgMSwgMCksCiAgICAgICAgIGRvdHcgPSB3ZGF5KG1keShzY2hlZHVsZV9kYXRlKSksCiAgICAgICAgIHRvdGFsX3BvaW50cyA9IHNjb3JlX2hvbWUgKyBzY29yZV9hd2F5KQoKYmFyX2dyb3VwMiA8LSBiYXJfZ3JvdXAgJT4lCiAgbXV0YXRlKHllYXIgPSB5ZWFyKHltZChkYXRlKSkpCgpiYXJfcHJlcCA8LSBiYXJfZ3JvdXAgJT4lCiAgZ3JvdXBfYnkoZGF0ZSwgZ2FtZWRheSwgaG91cl8pICU+JQogIHN1bW1hcml6ZShjcmltZXNfcGVyX2hvdXIgPSBzdW0oY291bnQpKSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkKCmJhcl9hdmVyYWdlcyA8LSBiYXJfcHJlcCAlPiUKICBncm91cF9ieShob3VyXywgZ2FtZWRheSkgJT4lCiAgc3VtbWFyaXplKGF2Z19wZXJfaG91ciA9IG1lYW4oY3JpbWVzX3Blcl9ob3VyKSkKCiMgdGVzdF9hdmVyYWdlcyA8LSB0ZXN0X2F2ZXJhZ2VzWy00OSxdCiAgCmJhcl9hdmVyYWdlc1tpcy5uYShiYXJfYXZlcmFnZXMpXSA8LSAwCgpiYXJfdGFibGUgPC0gYmFyX2F2ZXJhZ2VzICU+JQogIGdyb3VwX2J5KGdhbWVkYXkpICU+JQogIHN1bW1hcml6ZShwZXJfaG91cl9hdmcgPSBtZWFuKGF2Z19wZXJfaG91cikpCgojIERUOjpkYXRhdGFibGUoYmFyX3RhYmxlLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSxzY3JvbGxYPSc0MDBweCcpKQprYWJsZShiYXJfdGFibGUsICJzaW1wbGUiKQpgYGAKCkFjY29yZGluZyB0byB0aGlzIGFuYWx5c2lzLCBiYXJzIGFyZSBhY3R1YWxseSBhIGJpdCBzYWZlciBvbiBkYXlzIG9mIGFuIEVhZ2xlcyBnYW1lLiAKCmBgYHtyLCBjYWNoZT1UUlVFfQpiYXJfY2F0X3ByZXAgPC0gYmFyX2dyb3VwICU+JQogIGdyb3VwX2J5KGRhdGUsIGdhbWVkYXksIGNhdGVnb3J5LCBob3VyXykgJT4lCiAgc3VtbWFyaXplKGNyaW1lc19wZXJfaG91ciA9IHN1bShjb3VudCkpICU+JQogIHN0X2Ryb3BfZ2VvbWV0cnkoKQoKYmFyX2NhdF9hdmVyYWdlcyA8LSBiYXJfY2F0X3ByZXAgJT4lCiAgZ3JvdXBfYnkoaG91cl8sIGdhbWVkYXksIGNhdGVnb3J5KSAlPiUKICBzdW1tYXJpemUoYXZnX3Blcl9ob3VyID0gbWVhbihjcmltZXNfcGVyX2hvdXIpKQoKYmFyX2NhdF9hdmVyYWdlc1tpcy5uYShiYXJfY2F0X2F2ZXJhZ2VzKV0gPC0gMAoKYmFyX2NhdF90YWJsZSA8LSBiYXJfY2F0X2F2ZXJhZ2VzICU+JQogIGdyb3VwX2J5KGdhbWVkYXksY2F0ZWdvcnkpICU+JQogIHN1bW1hcml6ZShwZXJfaG91cl9hdmcgPSBtZWFuKGF2Z19wZXJfaG91cikpCgpnZ3Bsb3QoYmFyX2NhdF90YWJsZSwgCiAgICAgICBhZXMoeCA9IHJlb3JkZXIoY2F0ZWdvcnksIC1wZXJfaG91cl9hdmcpLAogICAgICAgICAgIHkgPSBwZXJfaG91cl9hdmcsCiAgICAgICAgICAgY29sb3IgPSBhcy5mYWN0b3IoZ2FtZWRheSksCiAgICAgICAgICAgZ3JvdXAgPSBhcy5mYWN0b3IoZ2FtZWRheSkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgcGxvdFRoZW1lICsKICBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgQ3JpbWVzIFBlciBIb3VyIFdpdGhpbiAyIEJsb2NrcyBvZiBCYXJzICYgUHVicyIpKwogIHBsb3RUaGVtZQoKYGBgCgoKYGBge3IsIGNhY2hlPVRSVUV9CmJhcl9jYXRfcHJlcCA8LSBiYXJfZ3JvdXAyICU+JQogIGdyb3VwX2J5KGRhdGUsIHllYXIsIGdhbWVkYXksIGNhdGVnb3J5LCBob3VyXykgJT4lCiAgc3VtbWFyaXplKGNyaW1lc19wZXJfaG91ciA9IHN1bShjb3VudCkpICU+JQogIHN0X2Ryb3BfZ2VvbWV0cnkoKQoKYmFyX2NhdF9hdmVyYWdlcyA8LSBiYXJfY2F0X3ByZXAgJT4lCiAgZ3JvdXBfYnkoeWVhciwgaG91cl8sIGdhbWVkYXksIGNhdGVnb3J5KSAlPiUKICBzdW1tYXJpemUoYXZnX3Blcl9ob3VyID0gbWVhbihjcmltZXNfcGVyX2hvdXIpKQoKYmFyX2NhdF9hdmVyYWdlc1tpcy5uYShiYXJfY2F0X2F2ZXJhZ2VzKV0gPC0gMAoKYmFyX2NhdF90YWJsZSA8LSBiYXJfY2F0X2F2ZXJhZ2VzICU+JQogIGdyb3VwX2J5KHllYXIsZ2FtZWRheSxjYXRlZ29yeSkgJT4lCiAgc3VtbWFyaXplKHBlcl9ob3VyX2F2ZyA9IG1lYW4oYXZnX3Blcl9ob3VyKSkKCmdncGxvdChiYXJfY2F0X3RhYmxlLCAKICAgICAgIGFlcyh4ID0gcmVvcmRlcihjYXRlZ29yeSwgLXBlcl9ob3VyX2F2ZyksCiAgICAgICAgICAgeSA9IHBlcl9ob3VyX2F2ZywKICAgICAgICAgICBjb2xvciA9IGFzLmZhY3RvcihnYW1lZGF5KSwKICAgICAgICAgICBncm91cCA9IGFzLmZhY3RvcihnYW1lZGF5KSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsKICBwbG90VGhlbWUgKwogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBDcmltZXMgUGVyIEhvdXIgV2l0aGluIDIgQmxvY2tzIG9mIEJhcnMgJiBQdWJzIiwKICAgICAgIHN1YnRpdGxlID0gIkJ5IFllYXIiKSsKICBmYWNldF93cmFwKH55ZWFyLCBzY2FsZXMgPSAiZnJlZSIpKwogIHBsb3RUaGVtZQpgYGAKCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KIyB0cmFjdF9qb2luZWQgPC0gc3Rfam9pbih0cmFjdHMsIHBobENyaW1lLCBqb2luID0gc3RfaW50ZXJzZWN0cykKIyAKIyB0cmFjdF9zdW1tYXJ5IDwtIHRyYWN0X2pvaW5lZCAlPiUKIyAgIGdyb3VwX2J5KEdFT0lEMTApICU+JQojICAgc3VtbWFyaXplKGNyaW1lX2NvdW50ID0gc3VtKGNvdW50KSkKIyAKIyBxQnIgPC0gZnVuY3Rpb24oZGYsIHZhcmlhYmxlLCBybmQpIHsKIyAgIGlmIChtaXNzaW5nKHJuZCkpIHsKIyAgICAgYXMuY2hhcmFjdGVyKHF1YW50aWxlKHJvdW5kKGRmW1t2YXJpYWJsZV1dLDApLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgYyguMDEsLjIsLjQsLjYsLjgpLCBuYS5ybT1UKSkKIyAgIH0gZWxzZSBpZiAocm5kID09IEZBTFNFIHwgcm5kID09IEYpIHsKIyAgICAgYXMuY2hhcmFjdGVyKGZvcm1hdEMocXVhbnRpbGUoZGZbW3ZhcmlhYmxlXV0pLCBkaWdpdHMgPSAzKSwKIyAgICAgICAgICAgICAgICAgIGMoLjAxLC4yLC40LC42LC44KSwgbmEucm09VCkKIyAgIH0KIyB9CiMgCiMgcTUgPC0gZnVuY3Rpb24odmFyaWFibGUpIHthcy5mYWN0b3IobnRpbGUodmFyaWFibGUsIDUpKX0KIyAKIyBnZ3Bsb3QoKSArCiMgICBnZW9tX3NmKGRhdGEgPSB0cmFjdF9zdW1tYXJ5LCBhZXMoZmlsbCA9IHE1KGNyaW1lX2NvdW50KSksIGNvbG9yID0gInRyYW5zcGFyZW50IikgKwojICAgc2NhbGVfY29sb3JfdmlyaWRpcyhuYW1lPSJUb3RhbCBDcmltZXNcbihRdWludGlsZSBCcmVha3MpIikgKwojICAgZ2VvbV9zZihkYXRhID0gcGhsT3V0bGluZSwgZmlsbCA9ICJ0cmFuc3BhcmVudCIsIHNpemUgPSAxLCBjb2xvciA9ICJibGFjayIpICsKIyAgIGxhYnModGl0bGU9IlRvdGFsIENyaW1lcyIsIAojICAgICAgICBzdWJ0aXRsZT0iMjAxOSIpKwojICAgbWFwVGhlbWUKYGBgCgojIyA1LjMgU0VQVEEgU3RhdGlvbnMKClRoZSBmaW5hbCBsb2NhbCBmZWF0dXJlIGluIHRoaXMgYXNzZXNzbWVudCB3aWxsIGJlIHN0YXRpb25zIGZyb20gU0VQVEEncyBCcm9hZCBTdHJlZXQgYW5kIE1hcmtldCBGcmFua2ZvcmQgbGluZXMuIEZpcnN0LCBsZXQncyB0YWtlIGEgbG9vayBhdCBjcmltZSBzdXJyb3VuZGluZyB0aGVzZSBzdGF0aW9ucyBmb3IgdGhlIGVudGlyZSB5ZWFyIG9mIDIwMTkuIFN1YndheSBzdG9wcywgYW5kIG90aGVyIHRyYW5zcG9ydGF0aW9uIGh1YnMsIGFyZSBrbm93biB0byBiZSBjcmltZSBnZW5lcmF0b3JzLiAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIGNyaW1lX2pvaW5lZCR5bWRfaG1zIDwtIHBhc3RlKGNyaW1lX2pvaW5lZCRkaXNwYXRjaF9kLCBjcmltZV9qb2luZWQkZGlzcGF0Y2hfdCkKIyAKIyBjbGVhbmVkX2NyaW1lIDwtIGNyaW1lX2pvaW5lZCAlPiUKIyAgIG11dGF0ZShpbnRlcnZhbDYwID0gZmxvb3JfZGF0ZSh5bWRfaG1zKHltZF9obXMpLCB1bml0ID0gImhvdXIiKSwKIyAgICAgICAgICBpbnRlcnZhbDE1ID0gZmxvb3JfZGF0ZSh5bWRfaG1zKHltZF9obXMpLCB1bml0ID0gIjE1IG1pbnMiKSkKCmdhbWVkYXlfdHJhY3RzIDwtIHN0X2pvaW4odHJhY3RzLCBjcmltZV9qb2luZWQsIGpvaW4gPSBzdF9pbnRlcnNlY3RzKQoKdHJhY3Rfc3VtbWFyeSA8LSBnYW1lZGF5X3RyYWN0cyAlPiUKICBncm91cF9ieShHRU9JRDEwKSAlPiUKICBzdW1tYXJpemUoY3JpbWVfY291bnQgPSBzdW0oY291bnQpKQoKY2xpcCA8LSAKICBzdF9pbnRlcnNlY3Rpb24oc2VwdGFCdWZmZXIsIHRyYWN0X3N1bW1hcnkpICU+JQogIGRwbHlyOjpzZWxlY3QoY3JpbWVfY291bnQpICU+JQogIG11dGF0ZShTZWxlY3Rpb25fVHlwZSA9ICJDbGlwIikKCnFCciA8LSBmdW5jdGlvbihkZiwgdmFyaWFibGUsIHJuZCkgewogIGlmIChtaXNzaW5nKHJuZCkpIHsKICAgIGFzLmNoYXJhY3RlcihxdWFudGlsZShyb3VuZChkZltbdmFyaWFibGVdXSwwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjKC4wMSwuMiwuNCwuNiwuOCksIG5hLnJtPVQpKQogIH0gZWxzZSBpZiAocm5kID09IEZBTFNFIHwgcm5kID09IEYpIHsKICAgIGFzLmNoYXJhY3Rlcihmb3JtYXRDKHF1YW50aWxlKGRmW1t2YXJpYWJsZV1dKSwgZGlnaXRzID0gMyksCiAgICAgICAgICAgICAgICAgYyguMDEsLjIsLjQsLjYsLjgpLCBuYS5ybT1UKQogIH0KfQoKcTUgPC0gZnVuY3Rpb24odmFyaWFibGUpIHthcy5mYWN0b3IobnRpbGUodmFyaWFibGUsIDUpKX0KCmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGE9cGhsT3V0bGluZSkgKwogIGdlb21fc2YoZGF0YSA9IHRyYWN0cywgc2l6ZSA9MC4yLCBjb2xvciA9ICJncmV5ODUiLCBmaWxsID0gImdyYXk5OCIpICsKICBnZW9tX3NmKGRhdGE9Y2xpcCwgCiAgICAgICAgICBhZXMoZmlsbD1xNShjcmltZV9jb3VudCkpLCAKICAgICAgICAgIGNvbG9yID0gInRyYW5zcGFyZW50IikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGxhYmVscz1xQnIoY2xpcCwiY3JpbWVfY291bnQiKSwgCiAgICAgICAgICAgICAgICAgICAgIG5hbWU9IlRvdGFsIENyaW1lXG4oUXVpbnRpbGUgQnJlYWtzKSIpICsKICAjIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMjk5OEMzIiwiIzI1ODZBRCIsIiMyMDc1OTYiLCIjMUI2MzgwIiwiIzE2NTI2OSIpLAogICMgICAgICAgICAgICAgICAgICAgbGFiZWxzPXFCcihjbGlwLCJjcmltZV9jb3VudCIpLAogICMgICAgICAgICAgICAgICAgICAgbmFtZT0iVG90YWwgQ3JpbWVcbihRdWludGlsZSBCcmVha3MpIikrCiAgZ2VvbV9zZihkYXRhPXBobE91dGxpbmUsIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBzaXplID0gMSkgKwogICMgZ2VvbV9zZihkYXRhID0gc2VwdGFfc3RvcHMsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDAuMSkgKwogIGxhYnModGl0bGU9IlRvdGFsIENyaW1lcyBXaXRoaW4gNTAwIG0uIG9mIFNFUFRBIFN0b3BzIiwgCiAgICAgICBzdWJ0aXRsZT0iMjAxOSIpICsKICBtYXBUaGVtZQpgYGAKCmBgYHtyLCBjYWNoZT1UUlVFfQpzZXB0YV9qb2luZWQgPC0gc3Rfam9pbihzZXB0YUJ1ZmZlciwgYWxsX2NhdGVnb3JpZXMsIGpvaW4gPSBzdF9pbnRlcnNlY3RzKQoKc2VwdGFfZ3JvdXAgPC0gbGVmdF9qb2luKHNlcHRhX2pvaW5lZCwgY29ycl9kYXRhLCBieSA9ICJkYXRlIikgJT4lCiAgbXV0YXRlKGhvbWVfZ2FtZSA9IGlmZWxzZSh0ZWFtX2hvbWUgPT0gIlBoaWxhZGVscGhpYSBFYWdsZXMiLCAxLCAwKSwKICAgICAgICAgYXdheV9nYW1lID0gaWZlbHNlKHRlYW1fYXdheSA9PSAiUGhpbGFkZWxwaGlhIEVhZ2xlcyIsIDEsIDApLAogICAgICAgICBmYXZvcml0ZSA9IGlmZWxzZSh0ZWFtX2Zhdm9yaXRlX2lkID09ICJQSEkiLCAxLCAwKSwKICAgICAgICAgcml2YWxyeSA9IGlmZWxzZSh0ZWFtX2hvbWUgPT0gIkRhbGxhcyBDb3dib3lzIiB8IHRlYW1faG9tZSA9PSAiV2FzaGluZ3RvbiBSZWRza2lucyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVhbV9ob21lID09ICJOZXcgWW9yayBHaWFudHMiIHwgdGVhbV9hd2F5ID09ICJEYWxsYXMgQ293Ym95cyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVhbV9hd2F5ID09ICJXYXNoaW5ndG9uIFJlZHNraW5zIiB8IHRlYW1fYXdheSA9PSAiTmV3IFlvcmsgR2lhbnRzIiwgMSwgMCksCiAgICAgICAgIGdhbWVkYXkgPSBpZmVsc2Uoc2NoZWR1bGVfcGxheW9mZiA9PSAiVFJVRSIgfCBzY2hlZHVsZV9wbGF5b2ZmID09ICJGQUxTRSIsIDEsIDApLAogICAgICAgICBkb3R3ID0gd2RheShtZHkoc2NoZWR1bGVfZGF0ZSkpLAogICAgICAgICB0b3RhbF9wb2ludHMgPSBzY29yZV9ob21lICsgc2NvcmVfYXdheSkKCiMgU0VQQVJBVEUgQlkgR0FNRURBWSBGSVJTVCAtIGZhY2V0IHdyYXAgd2lsbCB1c2Ugc2FtZSBzY2FsZS4KCnNlcHRhX2dyb3VwMiA8LSBzZXB0YV9ncm91cCAlPiUKICBtdXRhdGUoeWVhciA9IHllYXIoeW1kKGRhdGUpKSkKCnNlcHRhX3ByZXAgPC0gc2VwdGFfZ3JvdXAgJT4lCiAgZ3JvdXBfYnkoZGF0ZSwgZ2FtZWRheSwgaG91cl8pICU+JQogIHN1bW1hcml6ZShjcmltZXNfcGVyX2hvdXIgPSBzdW0oY291bnQpKSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkKCnNlcHRhX2F2ZXJhZ2VzIDwtIHNlcHRhX3ByZXAgJT4lCiAgZ3JvdXBfYnkoaG91cl8sIGdhbWVkYXkpICU+JQogIHN1bW1hcml6ZShhdmdfcGVyX2hvdXIgPSBtZWFuKGNyaW1lc19wZXJfaG91cikpCgojIHRlc3RfYXZlcmFnZXMgPC0gdGVzdF9hdmVyYWdlc1stNDksXQogIApzZXB0YV9hdmVyYWdlc1tpcy5uYShzZXB0YV9hdmVyYWdlcyldIDwtIDAKCnNlcHRhX3RhYmxlIDwtIHNlcHRhX2F2ZXJhZ2VzICU+JQogIGdyb3VwX2J5KGdhbWVkYXkpICU+JQogIHN1bW1hcml6ZShwZXJfaG91cl9hdmcgPSBtZWFuKGF2Z19wZXJfaG91cikpCgojIERUOjpkYXRhdGFibGUoc2VwdGFfdGFibGUsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1LHNjcm9sbFg9JzQwMHB4JykpCmthYmxlKHNlcHRhX3RhYmxlLCAic2ltcGxlIikKYGBgCgpgYGB7cn0Kc2VwdGFfY2F0X3ByZXAgPC0gc2VwdGFfZ3JvdXAgJT4lCiAgZ3JvdXBfYnkoZGF0ZSwgZ2FtZWRheSwgY2F0ZWdvcnksIGhvdXJfKSAlPiUKICBzdW1tYXJpemUoY3JpbWVzX3Blcl9ob3VyID0gc3VtKGNvdW50KSkgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpCgpzZXB0YV9jYXRfYXZlcmFnZXMgPC0gc2VwdGFfY2F0X3ByZXAgJT4lCiAgZ3JvdXBfYnkoaG91cl8sIGdhbWVkYXksIGNhdGVnb3J5KSAlPiUKICBzdW1tYXJpemUoYXZnX3Blcl9ob3VyID0gbWVhbihjcmltZXNfcGVyX2hvdXIpKQoKI0VSUk9SIC0gY2FudCBjb252ZXJ0IGRvdWJsZSB0byBjaGFyYWN0ZXI/CnNlcHRhX2NhdF9hdmVyYWdlcyA8LSBhcy5kYXRhLmZyYW1lKHNlcHRhX2NhdF9hdmVyYWdlcykKc2VwdGFfY2F0X2F2ZXJhZ2VzW2lzLm5hKHNlcHRhX2NhdF9hdmVyYWdlcyldID0gMAoKc2VwdGFfY2F0X3RhYmxlIDwtIHNlcHRhX2NhdF9hdmVyYWdlcyAlPiUKICBncm91cF9ieShnYW1lZGF5LGNhdGVnb3J5KSAlPiUKICBzdW1tYXJpemUocGVyX2hvdXJfYXZnID0gbWVhbihhdmdfcGVyX2hvdXIpKQoKZ2dwbG90KHNlcHRhX2NhdF90YWJsZSwgCiAgICAgICBhZXMoeCA9IHJlb3JkZXIoY2F0ZWdvcnksIC1wZXJfaG91cl9hdmcpLAogICAgICAgICAgIHkgPSBwZXJfaG91cl9hdmcsCiAgICAgICAgICAgY29sb3IgPSBhcy5mYWN0b3IoZ2FtZWRheSksCiAgICAgICAgICAgZ3JvdXAgPSBhcy5mYWN0b3IoZ2FtZWRheSkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgcGxvdFRoZW1lICsKICBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgQ3JpbWVzIFBlciBIb3VyIFdpdGhpbiAyIEJsb2NrcyBvZiBTRVBUQSBTdG9wcyIpKwogIHBsb3RUaGVtZQpgYGAKCmBgYHtyfQpzZXB0YV9jYXRfcHJlcCA8LSBzZXB0YV9ncm91cDIgJT4lCiAgZ3JvdXBfYnkoZGF0ZSwgeWVhciwgZ2FtZWRheSwgY2F0ZWdvcnksIGhvdXJfKSAlPiUKICBzdW1tYXJpemUoY3JpbWVzX3Blcl9ob3VyID0gc3VtKGNvdW50KSkgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpCgpzZXB0YV9jYXRfYXZlcmFnZXMgPC0gc2VwdGFfY2F0X3ByZXAgJT4lCiAgZ3JvdXBfYnkoeWVhciwgaG91cl8sIGdhbWVkYXksIGNhdGVnb3J5KSAlPiUKICBzdW1tYXJpemUoYXZnX3Blcl9ob3VyID0gbWVhbihjcmltZXNfcGVyX2hvdXIpKQoKc2VwdGFfY2F0X2F2ZXJhZ2VzIDwtIGFzLmRhdGEuZnJhbWUoc2VwdGFfY2F0X2F2ZXJhZ2VzKQpzZXB0YV9jYXRfYXZlcmFnZXNbaXMubmEoc2VwdGFfY2F0X2F2ZXJhZ2VzKV0gPC0gMAoKc2VwdGFfY2F0X3RhYmxlIDwtIHNlcHRhX2NhdF9hdmVyYWdlcyAlPiUKICBncm91cF9ieSh5ZWFyLGdhbWVkYXksY2F0ZWdvcnkpICU+JQogIHN1bW1hcml6ZShwZXJfaG91cl9hdmcgPSBtZWFuKGF2Z19wZXJfaG91cikpCgpnZ3Bsb3Qoc2VwdGFfY2F0X3RhYmxlLCAKICAgICAgIGFlcyh4ID0gcmVvcmRlcihjYXRlZ29yeSwgLXBlcl9ob3VyX2F2ZyksCiAgICAgICAgICAgeSA9IHBlcl9ob3VyX2F2ZywKICAgICAgICAgICBjb2xvciA9IGFzLmZhY3RvcihnYW1lZGF5KSwKICAgICAgICAgICBncm91cCA9IGFzLmZhY3RvcihnYW1lZGF5KSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsKICBwbG90VGhlbWUgKwogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBDcmltZXMgUGVyIEhvdXIgV2l0aGluIDIgQmxvY2tzIG9mIFNFUFRBIFN0b3BzIiwKICAgICAgIHN1YnRpdGxlID0gIkJ5IFllYXIiKSsKICBmYWNldF93cmFwKH55ZWFyLCBzY2FsZXMgPSAiZnJlZSIpKwogIHBsb3RUaGVtZQpgYGAKCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KIyBncmFkdWF0ZWQgc3Vid2F5IHN0b3Agc3ltYm9sIGZvciBnYW1lZGF5IHZzIG5vbiBnYW1lZGF5CiMgbmVlZCBpbmRpdmlkdWFsIHN0YXRpb24gYnVmZmVycyBhbmQgam9pbiB0byBjZW50cm9pZCBvZiB0cmFjdAoKIyBzZXB0YUJ1ZmZlcnMgPC0gc3RfYnVmZmVyKHNlcHRhX3N0b3BzLCA1MDApICU+JQojICAgc3RfdHJhbnNmb3JtKCJFUFNHOjM4NTciKQojIAojIAojIGFsbFRyYWN0cy5ncm91cCA8LQojICAgICBzdF9jZW50cm9pZChnYW1lZGF5X3RyYWN0cylbc2VwdGFCdWZmZXIsXSAlPiUKIyAgICAgICBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lCiMgICAgICAgbGVmdF9qb2luKGdhbWVkYXlfdHJhY3RzKSAlPiUKIyAgICAgICBzdF9zZigpIAojIAojIGdyYWR1YXRlZF9kYXRhIDwtIHN0X2pvaW4oc2VwdGFCdWZmZXJzLCBzdF9jZW50cm9pZChhbGxUcmFjdHMuZ3JvdXApKSAlPiUKIyAgIGdyb3VwX2J5KFN0YXRpb24sIGdhbWVkYXkpICU+JQojICAgc3VtbWFyaXplKGNyaW1lX3RvdGFsID0gc3VtKGNvdW50KSkgJT4lCiMgICB1bmdyb3VwKCkgJT4lCiMgICBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lCiMgICBsZWZ0X2pvaW4oc2VwdGFfc3RvcHMpICU+JQojICAgc3Rfc2YoKQojIAojIGdhbWVkYXlfZ3JhZCA8LSBncmFkdWF0ZWRfZGF0YSAlPiUKIyAgIGZpbHRlcihnYW1lZGF5ID09IDEpCiMgCiMgZ3JhZHVhdGVkX2RhdGEkZ2FtZWRheVtpcy5uYShncmFkdWF0ZWRfZGF0YSRnYW1lZGF5KV0gPC0gMAojIAojIG5vbmdhbWVkYXlfZ3JhZCA8LSBncmFkdWF0ZWRfZGF0YSAlPiUKIyAgIGZpbHRlcihnYW1lZGF5ICE9IDEpCiMgCiMgZ2FtZWRheV9tYXAgPC0gZ2dwbG90KCkgKwojICAgZ2VvbV9zZihkYXRhID0gcGhsT3V0bGluZSkgKwojICAgZ2VvbV9zZihkYXRhID0gZ2FtZWRheV9ncmFkLCBjb2xvciA9ICIjMTY1MjY5IiwgYWxwaGEgPSAwLjc1LCBhZXMoc2l6ZSA9IGNyaW1lX3RvdGFsKSkgKwojICAgbGFicyh0aXRsZSA9ICJHYW1lIERheXMiLCAKIyAgICAgICAgc3VidGl0bGUgPSAiMjAxOSIpICsKIyAgIG1hcFRoZW1lCiMgCiMgbm9uZ2FtZWRheV9tYXAgPC0gZ2dwbG90KCkgKwojICAgZ2VvbV9zZihkYXRhID0gcGhsT3V0bGluZSkgKwojICAgZ2VvbV9zZihkYXRhID0gbm9uZ2FtZWRheV9ncmFkLCBjb2xvciA9ICIjMTY1MjY5IiwgYWxwaGEgPSAwLjc1LCBhZXMoc2l6ZSA9IGNyaW1lX3RvdGFsKSkgKwojICAgbGFicyh0aXRsZSA9ICJOb24gR2FtZSBEYXlzIiwgCiMgICAgICAgIHN1YnRpdGxlID0gIjIwMTkiKSArCiMgICBtYXBUaGVtZQojIAojIGdyaWQuYXJyYW5nZShnYW1lZGF5X21hcCwgbm9uZ2FtZWRheV9tYXAsIG5yb3cgPSAxKQpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQoKIyAKIyBnYW1lZGF5dHJhY3Rfc3VtbWFyeSA8LSBnYW1lZGF5X3RyYWN0cyAlPiUKIyAgIGdyb3VwX2J5KEdFT0lEMTAsIGdhbWVkYXksIGludGVydmFsNjApICU+JQojICAgc3VtbWFyaXplKGNyaW1lX2NvdW50ID0gc3VtKGNvdW50KSkKIyAKIyBnYW1lZGF5dHJhY3Rfc3VtbWFyeVtbImdhbWVkYXkiXV1baXMubmEoZ2FtZWRheXRyYWN0X3N1bW1hcnlbWyJnYW1lZGF5Il1dKV0gPC0gMAojIAojIGdhbWVkYXlfYW5pbWF0aW9uX2RhdGEgPC0gZ2FtZWRheXRyYWN0X3N1bW1hcnkgCgoKCgoKIyBtaWdodCBuZWVkIHRvIGRvIHRoaXMgYXQgdGhlIHZlcnkgYmVnaW5uaW5nIHRvIG92ZXJ3cml0ZSB0aGUgY3JpbWUgZmlsZSB0aGF0IGdhbWVkYXlfdHJhY3RzIHdhcyBjcmVhdGVkIHdpdGggCiMgd2h5IGlzbnQgaXQgc2hvd2luZyAwJ3M/Pz8/IEl0IHNraXBzIGludGVydmFscyB3aXRoIG5vIGNyaW1lcwoKIyBnYW1lZGF5X2FuaW1hdGlvbjIgPC0gCiMgICBnZ3Bsb3QoKSsKIyAgIGdlb21fc2YoZGF0YSA9IHRyYWN0cywgZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG9yPSJibGFjayIsIHNpemU9MikgKwojICAgZ2VvbV9zZihkYXRhID0gdHJhY3RzLCBzaXplID0gMC4yLCBjb2xvciA9ICJncmV5ODUiLCBmaWxsID0gImdyZXk5OCIpICsKIyAgIGdlb21fc2YoZGF0YSA9IGdhbWVkYXlfYW5pbWF0aW9uX2RhdGEsCiMgICAgICAgICAgIGFlcyhmaWxsPWNyaW1lX2NvdW50LCBnZW9tZXRyeSA9IGdlb21ldHJ5KSwKIyAgICAgICAgICAgY29sb3IgPSAidHJhbnNwYXJlbnQiLCBhbHBoYSA9IDAuOCkgKwojICAgZ2VvbV9zZihkYXRhID0gbGluYywgc2l6ZSA9IDAuNzUpICsKIyAgIGdlb21fc2YoZGF0YSA9IGxpbmNCdWZmZXIsIGNvbG9yID0gInJlZCIsIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBzaXplID0gMC4zKSArCiMgICBnZW9tX3NmKGRhdGEgPSBzdF91bmlvbihzZXB0YUJ1ZmZlciksIGNvbG9yID0gInJlZCIsIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBzaXplID0gMC4yKSArCiMgICBzY2FsZV9maWxsX3ZpcmlkaXMoIkNyaW1lcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICBkaXNjcmV0ZSA9IEZBTFNFLCAKIyAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbiA9ICJEIikgKwojICAgbGFicyh0aXRsZT0iVG90YWwgQ3JpbWVzOiB7Y3VycmVudF9mcmFtZX0iLAojICAgICAgICBzdWJ0aXRsZSA9ICI2MCBtaW51dGUgaW50ZXJ2YWxzIikgKwojICAgbWFwVGhlbWUgKwojICAgICBlbnRlcl9mYWRlKCkgKyAKIyAgICAgZXhpdF9zaHJpbmsoKSArCiMgICB0cmFuc2l0aW9uX21hbnVhbChpbnRlcnZhbDYwKQojIAojIGFuaW1hdGUoZ2FtZWRheV9hbmltYXRpb24yLCBkdXJhdGlvbj0yOCwgcmVuZGVyZXIgPSBnaWZza2lfcmVuZGVyZXIoKSkKYGBgCgojIDYuIENvbmNsdXNpb24KCiMjIDYuMSBSZXN1bHRzIGFuZCBEaXNjdXNzaW9uCgpSZXBlYXRpbmcgdGhpcyBhbmFseXNpcyBvbiBhbm90aGVyIE5GTCB0ZWFtLCBwZXJoYXBzIGEgdGVhbSBpbiBhIHNtYWxsZXIgY2l0eSwgb3IgYSBjaXR5IHdoZXJlIGNyaW1lIGlzIGxlc3Mgb2YgYSBwcmV2YWxlbnQgaXNzdWUgdGhhbiBpdCBpcyBpbiBQaGlsYWRlbHBoaWEsIGNvdWxkIHByb3ZpZGUgZGlmZmVyZW50IHJlc3VsdHMuIFBoaWxhZGVscGhpYSBoYXMgYmVlbiBleHBlcmllbmNpbmcgaW5jcmVhc2luZyBjcmltZSByYXRlcyBmb3IgcXVpdGUgYSBmZXcgeWVhcnMgYXQgdGhpcyBwb2ludC4gUGFpcmluZyB0aGF0IHJlY2VudCB0cmVuZCB3aXRoIHRoZSBmYWN0IHRoYXQgUGhpbGFkZWxwaGlhIGlzIG9uZSBvZiB0aGUgbGFyZ2VzdCBjaXRpZXMgaW4gdGhlIGNvdW50cnkgb2ZmZXJzIGFuIGV4cGxhbmF0aW9uIGFzIHRvIHdoeSBjcmltZSBjb3VudHMgZG8gbm90IHNlZW0gdG8gY2hhbmdlIGJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiBhbiBFYWdsZXMgZ2FtZS4KCldoaWxlIHNvbWUgcmVzZWFyY2ggaGFzIGJlZW4gY29tcGxldGVkIG9uIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjcmltZSBhbmQgc3BvcnRzIHRlYW1zLCBvbmx5IGEgZmV3IG9mIHRoZXNlIGhhdmUgZGVhbHQgd2l0aCBwcm9mZXNzaW9uYWwgc3BvcnRzLCBhbmQgZXZlbiBmZXdlciBoYXZlIGFuYWx5emVkIE5GTCBGb290YmFsbC4gTm8gcmVzZWFyY2ggaGFzIGJlZW4gY29tcGxldGVkIGF0IHRoaXMgcG9pbnQgdGhhdCBpbmNsdWRlcyBhbnkgZ2Vvc3BhdGlhbCBhbmFseXNpcyBvZiB0aGlzIGxpbmUgb2Ygc3R1ZHkuCgoqKkluIHRoaXMgZ2Vvc3BhdGlhbCBhbmFseXNpcywgSSBmb3VuZCBpbmNyZWFzZXMgKG9mIHZhcnlpbmcgbGV2ZWxzKSBvbiBnYW1lIGRheXMgaW4gdGhlIGZvbGxvd2luZzoqKgoKKiBvdmVyYWxsIGNyaW1lIGR1cmluZyBvdmVybmlnaHQgaG91cnMKKiB0b3RhbCBjcmltZSB3aXRoaW4gMTAwMCBtZXRlcnMgb2YgTGluY29sbiBGaW5hbmNpYWwgRmllbGQsIHNwZWNpZmljYWxseToKICArIHRoZWZ0cwogICsgb3RoZXIgdW5saXN0ZWQgb2ZmZW5zZXMKICArIGZpbmFuY2lhbCBvZmZlbnNlcwoKKiphbmQgZ2FtZSBkYXkgZGVjcmVhc2VzIGluIHRoZSBmb2xsb3dpbmc6KioKCiogb3ZlcmFsbCBjcmltZSB3aXRoaW4gMiBibG9ja3Mgb2YgYmFycyBhbmQgcHVicywgc3BlY2lmaWNhbGx5OgogICsgb3RoZXIgdW5saXN0ZWQgb2ZmZW5zZXMKICArIHZpb2xlbnQgY3JpbWVzCiAgKyBhbGNvaG9saWMvbmFyY290aWMgb2ZmZW5zZXMKKiBvdmVyYWxsIGNyaW1lIHdpdGhpbiAyIGJsb2NrcyBvZiBTRVBUQSBzdGF0aW9ucwogICsgb3RoZXIgdW5saXN0ZWQgb2ZmZW5zZXMKICArIHZpb2xlbnQgY3JpbWVzCiAgKyB0aGVmdHMKICAKIyMgNi4yIExpbWl0YXRpb25zIGFuZCBGdXJ0aGVyIFJlc2VhcmNoCgpGdXJ0aGVyIHJlc2VhcmNoIHNob3VsZCBiZSBkb25lIGluIHRoaXMgYXJlYSB3aXRoIGEgbW9yZSBpbiBkZXB0aCBjb21wYXJpc29uLiBGb3IgaW5zdGFuY2UsIGluc3RlYWQgb2YgYWdncmVnYXRpbmcgYWxsIG5vbi1nYW1lIGRheXMgZnJvbSBhbiBlbnRpcmUgeWVhciBhbmQgY29tcGFyaW5nIHRoZW0gdG8ganVzdCAxNiBnYW1lIGRheXMsIG9ubHkgOCBvZiB3aGljaCBhcmUgaG9tZSBnYW1lcywgYSBtb3JlIHNlbGVjdGl2ZSBhcHByb2FjaCBjb3VsZCBiZSBjb25kdWN0ZWQuIFRvIGJlIHN1cmUgdGhpcyBhcHByb2FjaCBzZXRzIHVwIGEgc3Ryb25nZXIgYW5kIG1vcmUgZmFpciBjb21wYXJpc29uLCB0aGUgU3VuZGF5IG9mIGVhY2ggYnllLXdlZWsgZnJvbSB0aGUgc2Vhc29uIGNvdWxkIGJlIHVzZWQgYXMgYSBjb250cm9sLiBUaGF0IHdheSB0aGUgc2Vhc29uYWxpdHkgY2hhbmdlcyBwbGF5IGEgbWluaW1hbCByb2xlIGluIGFueSB2YXJpYW5jZS4gCgpJZiB0aGlzIHdlcmUgdG8gYmUgcmVwbGljYXRlZCBhbmQgaW1wcm92ZWQsIGFkZGl0aW9uYWwgYW5hbHlzaXMgc2hvdWxkIGJlIGNvbXBsZXRlZCBvbiB0aGUgaG91cnMgZHVyaW5nIGEgZ2FtZSwgYW5kIGZvciBob3VycyBmb2xsb3dpbmcgYSBnYW1lLiBBZGRpdGlvbmFsbHksIHRoaXMgZnVydGhlciBhbmFseXNpcyBzaG91bGQgYmUgY29tcGxldGVkIHdpdGggcmVzcGVjdCB0byB0aGUgZGlmZmVyZW50IGVmZmVjdHMgb2YgaG9tZSB2cy4gYXdheSBnYW1lcy4gQSBzdHJvbmdlciBjb250cm9sIG9yIG1ldGhvZCBvZiBzdGFuZGFyZGl6aW5nIHdpbGwgbGlrZWx5IHByb2R1Y2UgcmVzdWx0cyBzaW1pbGFyIHRvIHRob3NlIG9mIHRoZSByZXNlYXJjaCBtZW50aW9uZWQgaW4gdGhpcyByZXBvcnQuIAoKV2hpbGUgdGhpcyByZXBvcnQgd2FzIHNpbXBseSBtZWFudCBmb3IgZXhwbGFpbmluZyBwYXN0IGV2ZW50cywgY29ycmVsYXRpb25zLCBhbmQgcGF0dGVybnMsIHRoaXMgdHlwZSBvZiBhbmFseXNpcyBjb3VsZCBhYnNvbHV0ZWx5IHNlcnZlIGEgcmVhbCBwdXJwb3NlLiBJZiBpdCB3YXMgY29tcGxldGVkIHdpdGggYSBzdHJvbmdlciBjb250cm9sIGFuZCBjb21wYXJpc29uLCB0aGVyZSBpcyBubyByZWFzb24gYSBjb2xsZWdlIHRvd24gY291bGRuJ3QgdXNlIHRoaXMgZGF0YSBpbiBhIHByZWRpY3RpdmUgbW9kZWwgZnJvbSB3ZWVrZW5kIHRvIHdlZWtlbmQuIEtub3dpbmcgd2hhdCBmYWN0b3JzIGluZmx1ZW5jZSBjcmltZSBpbmNyZWFzZXMsIHN1Y2ggYXMgb3Bwb25lbnQsIGdhbWUgc3RhcnQgdGltZSwgb3IgdGltZSBvZiB5ZWFyIGNhbiBiZSBwaXZvdGFsIGluIHNtYWxsZXIgdG93bnMnIHJlc3BvbnNlcyB0byBjcmltZS4gT2J2aW91c2x5LCB0aGUgcmVndWxhciBjb25jZXJucyBvZiBwcmVkaWN0aXZlIHBvbGljaW5nIHdvdWxkIHN0aWxsIGFwcGx5IGFuZCByZXF1aXJlIHRoZSB1dG1vc3QgY2F1dGlvbiBhbmQgdW5iaWFzZWQgYXR0ZW50aW9uIGluIGRlc2lnbmluZyBzdWNoIGEgbW9kZWwsIGJ1dCB0aGUgdXNlIGNhc2UgaXMgZGVmaW5pdGVseSBleGlzdGVudC4g