Bring in the SW audit file from the BARI shared Google Drive and take a look at it. This should be the Sidewalk Audit conducted in… what year?

sw_pts <- st_read(dsn = "~/Google Drive/BARI Research Team Data Library/StreetCaster/Sidewalk Conditions T1/",layer="Sidewalk Centroids")
Reading layer `Sidewalk Centroids' from data source `/Users/justin/Google Drive/BARI Research Team Data Library/StreetCaster/Sidewalk Conditions T1' using driver `ESRI Shapefile'
Simple feature collection with 27388 features and 28 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: 741131.2 ymin: 2909796 xmax: 801864.4 ymax: 2969943
epsg (SRID):    NA
proj4string:    +proj=lcc +lat_1=41.71666666666667 +lat_2=42.68333333333333 +lat_0=41 +lon_0=-71.5 +x_0=199999.9999999999 +y_0=750000 +datum=NAD83 +units=us-ft +no_defs
sw_pts <- st_read(dsn = "~/Google Drive/BARI Research Team Data Library/StreetCaster/Sidewalk Conditions T1/",layer="Sidewalk Centroids")
Reading layer `Sidewalk Centroids' from data source `/Users/justin/Google Drive/BARI Research Team Data Library/StreetCaster/Sidewalk Conditions T1' using driver `ESRI Shapefile'
Simple feature collection with 27388 features and 28 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: 741131.2 ymin: 2909796 xmax: 801864.4 ymax: 2969943
epsg (SRID):    NA
proj4string:    +proj=lcc +lat_1=41.71666666666667 +lat_2=42.68333333333333 +lat_0=41 +lon_0=-71.5 +x_0=199999.9999999999 +y_0=750000 +datum=NAD83 +units=us-ft +no_defs
sw_poly <- st_read(dsn = "~/Google Drive/BARI Research Team Data Library/StreetCaster/Sidewalk Conditions T1/",layer="SWK_ANALYSIS")
Reading layer `SWK_ANALYSIS' from data source `/Users/justin/Google Drive/BARI Research Team Data Library/StreetCaster/Sidewalk Conditions T1' using driver `ESRI Shapefile'
Simple feature collection with 27388 features and 27 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: 741058.7 ymin: 2909733 xmax: 801961.7 ymax: 2969955
epsg (SRID):    NA
proj4string:    +proj=lcc +lat_1=41.71666666666667 +lat_2=42.68333333333333 +lat_0=41 +lon_0=-71.5 +x_0=199999.9999999999 +y_0=750000 +datum=NAD83 +units=us-ft +no_defs

Basic summary stats:

summary(sw_pts$TIMESTAMP)
           2/2/2012           3/26/2012          11/18/2011           3/27/2012 2009-08-05 10:20:04           1/16/2012 
                214                 144                 143                 136                 129                 123 
          2/14/2012            2/6/2012          11/15/2011            2/9/2012          12/16/2011          12/31/2011 
                117                 115                 112                 108                 107                 106 
           2/7/2012          11/21/2011          12/12/2011           2/23/2012            1/3/2012            1/9/2012 
                105                 103                  99                  98                  95                  95 
           2/1/2012           12/6/2011           1/24/2012          12/13/2011           1/18/2012          11/28/2011 
                 93                  92                  90                  89                  88                  88 
          2/13/2012            2/8/2012           1/25/2012           12/8/2011           12/9/2011          11/29/2011 
                 88                  88                  85                  85                  84                  82 
          12/1/2011            1/5/2012          12/15/2011           1/26/2012           2/15/2012           2/24/2012 
                 80                  78                  78                  76                  75                  74 
         11/22/2011            1/6/2012          12/14/2011           2/21/2012          11/30/2011           1/19/2012 
                 73                  72                  71                  71                  69                  68 
          1/31/2012           1/27/2012          11/23/2011           1/30/2012          11/16/2011           12/7/2011 
                 66                  65                  65                  57                  56                  55 
         11/17/2011           2/22/2012 2011-12-05 16:09:00            2/3/2012 2012-01-09 14:39:29 2009-11-20 14:26:02 
                 54                  52                  33                  31                  29                  23 
2012-02-29 10:29:09 2012-01-09 12:15:19           12/2/2011 2012-01-13 15:06:08 2010-03-10 12:06:45 2011-10-24 15:18:40 
                 23                  22                  21                  19                  18                  18 
2010-06-16 11:50:03 2011-12-05 16:47:10 2012-01-23 10:57:42 2011-12-05 16:48:23 2012-02-29 10:27:13 2011-07-25 11:48:10 
                 16                  16                  16                  15                  15                  14 
2011-08-29 11:21:35 2011-10-24 15:15:45 2012-02-29 10:37:03 2010-03-10 15:23:10 2010-06-16 11:43:44 2011-05-05 14:03:15 
                 14                  14                  14                  13                  13                  13 
2011-05-05 14:04:02 2012-02-29 10:32:33 2011-10-24 15:17:45 2012-01-09 14:00:13 2012-02-28 07:50:13 2012-02-29 10:36:30 
                 13                  13                  12                  12                  12                  12 
2010-02-23 10:22:11 2010-03-10 16:04:42 2010-06-18 12:57:31 2011-08-01 09:57:05 2012-01-03 12:16:36 2012-01-09 10:04:34 
                 11                  11                  11                  11                  11                  11 
2012-01-23 11:28:56 2012-02-29 10:32:01 2012-05-19 15:18:01 2010-03-10 15:36:40 2011-04-11 16:42:58 2011-11-16 15:20:42 
                 11                  11                  11                  10                  10                  10 
2011-12-05 11:58:05 2012-01-09 10:23:32 2012-02-22 11:39:59 2009-12-04 08:57:15 2011-04-25 11:53:19 2012-01-03 15:41:12 
                 10                  10                  10                   9                   9                   9 
2012-01-11 14:02:05 2012-02-13 09:06:34 2012-02-29 10:38:25             (Other) 
                  9                   9                   9               22135 
sw_pts$date2 <- parse_date_time(x = as.character(sw_pts$TIMESTAMP),
                            orders=c("mdY","Ymd HMS"), truncated = 3)
summary(sw_pts$date2) # goes from 2008 through 2012
                 Min.               1st Qu.                Median                  Mean               3rd Qu. 
"2008-12-04 12:59:15" "2011-06-03 08:27:06" "2011-12-16 12:57:41" "2011-09-02 00:27:31" "2012-02-10 08:48:37" 
                 Max. 
"2012-05-31 14:22:01" 
# pdf("figures/audit1_timeline.pdf",height=4,width=10)
hist(sw_pts$date2,breaks = "months",main="Timeline of Audit 1",xlab="Date of Assessment") # mostly in the early part of 2012.

# dev.off()
(dateplot1 <- ggplot(sw_pts) + 
      geom_histogram(aes(x=date2)) + 
      scale_x_datetime("Date of Assessment",date_minor_breaks="months",date_labels="%b %Y") + 
      theme_bw())

rr ggsave(dateplot1,file=/timeline1.pdf)

Saving 7 x 7 in image

So, it looks like this is the quality of the sidewalks

Okay, time to bring in the SCI report from T2:

summary(sw_pts_t2)
     SWK_ID         MATERIAL       SWK_WIDTH                DISTRICT        SWK_AREA         PARENT               SEG_ID     
 24478  :   13   CC     :19494   6      :4434   SOUTH DORCHESTER: 3017   1135   :   20   WASHI1 :  285   TLBRO1_14828:   14  
 17868  :    6   BR     : 1266   6.5    :3768   NORTH DORCHESTER: 2666   1210   :   19   CENTR6 :  239   DOONE1_122  :    6  
 17836  :    5   BC     :  897   7      :2206   WEST ROXBURY    : 2537   1163   :   18   DORCH1 :  196   SHAWM2_7336 :    6  
 372    :    5   CB     :  526   7.5    :1634   DOWNTOWN        : 2055   1334   :   18   RIVER1 :  162   SUMME9_1224 :    6  
 10342  :    4   UNK    :  303   0      :1454   ALLSTON/BRIGHTON: 2041   1452   :   18   WASHI5 :  127   WESTV1_0    :    6  
 (Other):23297   (Other):  177   (Other):9839   (Other)         :11014   (Other):23237   (Other):22321   (Other)     :23292  
 NA's   :   21   NA's   :  688   NA's   :  16   NA's            :   21   NA's   :   21   NA's   :   21   NA's        :   21  
    SIDE           CG_ID           Rpr_Yr          New_SCI         Recon_Date                  geometry    
 LEFT :11563   24258  :   13   Min.   :   0.0   Min.   :  0.00   Min.   :2010-05-05   POINT        :23351  
 RIGHT:11766   17759  :    6   1st Qu.:   0.0   1st Qu.: 45.00   1st Qu.:2014-04-16   epsg:NA      :    0  
 NA's :   22   17728  :    5   Median :   0.0   Median : 73.00   Median :2015-08-10   +proj=lcc ...:    0  
               10277  :    4   Mean   : 262.1   Mean   : 65.48   Mean   :2015-03-21                        
               18301  :    4   3rd Qu.:   0.0   3rd Qu.: 91.00   3rd Qu.:2016-07-21                        
               (Other):22901   Max.   :2016.0   Max.   :100.00   Max.   :2016-11-18                        
               NA's   :  418                                     NA's   :23094                             

Basic descriptives:

summary(sw_poly_t2$SWK_ID) # 5-digit ID numbers, but not unique?
  24478   17868   17836     372   10342   17286   17289   18411   22898   23153   23614   24230    9830   11012   11206 
     13       6       5       5       4       4       4       4       4       4       4       4       4       3       3 
  17839   17855   17861   17959   18460   19071   19135   19233   19682   21372   21443   21746   21846   22041   22116 
      3       3       3       3       3       3       3       3       3       3       3       3       3       3       3 
  22145   22170   22181   22221   22600   23144   23645   24159   24395   24446   24487   24488   24633    5271    5505 
      3       3       3       3       3       3       3       3       3       3       3       3       3       3       3 
  10861   11202   11280   11611   11697   11731   11736   12181   12434   13964   15753   16593   16740   16741   16744 
      2       2       2       2       2       2       2       2       2       2       2       2       2       2       2 
  16748   16821   16890   16957   16968   17018   17090   17142   17496   17834   17835   17860   17968    1829   18401 
      2       2       2       2       2       2       2       2       2       2       2       2       2       2       2 
  18404   18405   18534   18555   18605   18836   18948   19007    1937   20553   20666   21204   21209   21368   21447 
      2       2       2       2       2       2       2       2       2       2       2       2       2       2       2 
  21702   21887   21892   21897   21934   21937   22043   22099 (Other)    NA's 
      2       2       2       2       2       2       2       2   23063      21 
summary(sw_poly_t2$New_SCI) # 0-100 Sidewalk Condition Index
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.00   45.00   73.00   65.48   91.00  100.00 

Spatial visuals

Plot SCI:

New data:

Trying to match up geographies across two audits:

So no, those don’t match up. That’s a pain.

Check if the sidewalk segments match up from T1 to T2 at all

st_crs(sw_poly); st_crs(sw_poly_t2)
Coordinate Reference System:
  No EPSG code
  proj4string: "+proj=lcc +lat_1=41.71666666666667 +lat_2=42.68333333333333 +lat_0=41 +lon_0=-71.5 +x_0=199999.9999999999 +y_0=750000 +datum=NAD83 +units=us-ft +no_defs"
Coordinate Reference System:
  No EPSG code
  proj4string: "+proj=lcc +lat_1=41.71666666666667 +lat_2=42.68333333333333 +lat_0=41 +lon_0=-71.5 +x_0=199999.9999999999 +y_0=750000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=us-ft +no_defs"

Let’s look at some subsets to see how to match them spatially

Matching sidewalks segments across waves of audits

trying with centroid points:

rr

sw_pts_t2 <- st_transform(sw_pts_t2,st_crs(sw_pts)) # distmat <- st_distance(sw_pts,sw_pts_t2) # in ft (US) # closest <- apply(distmat,1,function(x){which(x==min(x))}) # closest_dist <- apply(distmat,1,min) # distance in feet # closest[10875] # plot(st_geometry(sw_poly_t2[c(13584,22947),_SCI])) # these are duplicates, that’s why! # closest[10875] <- 13584 # manual fix # matchtable <- tibble(index_t1 = 1:length(unlist(closest)), # closest_index = unlist(closest), # closest_dist = closest_dist, # SWK_ID_t1 = sw_pts\(SWK_ID) # matchtable\)SWK_ID_t2 <- sw_pts_t2\(SWK_ID[matchtable\)closest_index] # summary(matchtable\(closest_dist) # plot(st_geometry(sw_poly %>% filter(SWK_ID %in% matchtable\)SWK_ID_t1[8]))) # these should be overlapping # plot(st_geometry(sw_poly_t2 %>% filter(SWK_ID %in% matchtable$SWK_ID_t2[8])),add=T,col=) # shows that 44 ft apart in centroids not much

What about looking at some segments that are farther apart?

rr # matchtable %>% filter(closest_dist>1000)

rr # plot(st_geometry(sw_poly %>% filter(SWK_ID %in% matchtable\(SWK_ID_t1[8]))) # these should be overlapping # plot(st_geometry(sw_poly_t2 %>% filter(SWK_ID %in% matchtable\)SWK_ID_t2[8])),add=T,col=) # shows that 44 ft apart in centroids not much # plot(st_geometry(sw_poly %>% filter(SWK_ID %in% matchtable\(SWK_ID_t1[1181]))) # these should be overlapping # plot(st_geometry(sw_poly_t2 %>% filter(SWK_ID %in% matchtable\)SWK_ID_t2[1181])),add=T,col=) # shows that even 1047 ft apart in centroids not much, and probably a correct match! # #{r} # plot(st_geometry(sw_poly %>% filter(SWK_ID %in% matchtable\(SWK_ID_t1[1181:1187]))) # these should be overlapping # plot(st_geometry(sw_poly_t2 %>% filter(SWK_ID %in% matchtable\)SWK_ID_t2[1181:1187])),add=T,col=) # shows that even 1047 ft apart in centroids not much, and probably a correct match!

What this seems to be showing is that actually there are just some sidewalk segments that are missing in Wave 2 of the SCI survey. Shows we should also do the matching in the opposite direction - e.g. find closest segment to each SWK in wave 2 from wave 1.

Matching in opposite direction (wave 1 to wave 2):

rr # distmat2 <- st_distance(sw_pts_t2,sw_pts) # in ft (US) # closest2 <- apply(distmat2,1,function(x){which(x==min(x))}) # closest_dist2 <- apply(distmat2,1,min) # distance in feet # matchtable2 <- tibble(index_t2 = 1:length(unlist(closest2)), # closest_index = unlist(closest2), # closest_dist = closest_dist2, # SWK_ID_t2 = as.numeric(as.character(sw_pts_t2\(SWK_ID))) # matchtable2\)SWK_ID_t1 <- sw_pts\(SWK_ID[matchtable2\)closest_index] # summary(matchtable2$closest_dist) # maximum 1114 ft, which is totally allowable

Now, time to match and create over-time change metrics

rr # matchtable2\(SCI_t1 <- sw_pts\)SCI[match(matchtable2\(SWK_ID_t1,sw_pts\)SWK_ID)] # matchtable2\(SCI_t2 <- sw_pts_t2\)New_SCI[match(matchtable2\(SWK_ID_t2,sw_pts_t2\)SWK_ID)] # matchtable2 <- matchtable2 %>% # mutate(SCI_change = SCI_t2-SCI_t1, # SCI_change_perc = SCI_change/SCI_t1) # summary(matchtable2) # on average, got better by 0.1, but median = -1.39. percent messed up b/c some have SCI=0

Time to match these data back to the polygons

summary(sw_poly_t2)
     SWK_ID         MATERIAL       SWK_WIDTH                 DISTRICT        SWK_AREA         PARENT     
 Min.   :    1   CC     :20160   6      : 4584   SOUTH DORCHESTER: 3117   20209  :  169   WASHI1 :  295  
 1st Qu.: 6355   BR     : 1368   6.5    : 3800   NORTH DORCHESTER: 2710   16857  :   36   CENTR6 :  241  
 Median :12724   BC     :  909   7      : 2272   WEST ROXBURY    : 2543   12951  :   25   DORCH1 :  198  
 Mean   :12628   CB     :  562   7.5    : 1654   DOWNTOWN        : 2151   18198  :   25   TLBRO1 :  180  
 3rd Qu.:18907   UNK    :  312   0      : 1510   ALLSTON/BRIGHTON: 2063   2598   :   22   RIVER1 :  162  
 Max.   :24778   (Other):  191   (Other):10371   (Other)         :11502   (Other):23809   (Other):23010  
 NA's   :441     NA's   : 1025   NA's   :  336   NA's            :  441   NA's   :  441   NA's   :  441  
          SEG_ID         SIDE           CG_ID           Rpr_Yr          New_SCI         Recon_Date            index_t2    
 TLBRO1_14828:  170   LEFT :11839   24258  :  169   Min.   :   0.0   Min.   :  0.00   Min.   :2010-05-05   Min.   :    1  
 SUMME9_1224 :   36   RIGHT:12245   17759  :   36   1st Qu.:   0.0   1st Qu.: 45.00   1st Qu.:2013-09-23   1st Qu.: 6118  
 SHAWM2_7336 :   26   NA's :  443   17728  :   25   Median :   0.0   Median : 73.00   Median :2014-03-31   Median :12235  
 AMERI1_1688 :   25                 10277  :   16   Mean   : 254.7   Mean   : 65.67   Mean   :2014-07-21   Mean   :12204  
 DOONE1_122  :   20                 18301  :   16   3rd Qu.:   0.0   3rd Qu.: 92.00   3rd Qu.:2015-08-24   3rd Qu.:18352  
 (Other)     :23809                 (Other):23407   Max.   :2016.0   Max.   :100.00   Max.   :2016-11-18   Max.   :23351  
 NA's        :  441                 NA's   :  858                                     NA's   :23833                       
 closest_index    closest_dist        SWK_ID_t1         SCI_t1           SCI_t2         SCI_change        SCI_change_perc  
 Min.   :    1   Min.   :   0.000   Min.   :    2   Min.   :  0.00   Min.   :  0.00   Min.   :-100.0000   Min.   :-1.0000  
 1st Qu.: 7038   1st Qu.:   1.953   1st Qu.: 8472   1st Qu.: 44.97   1st Qu.: 45.00   1st Qu.: -10.3604   1st Qu.:-0.1636  
 Median :13800   Median :   4.838   Median :15801   Median : 71.65   Median : 73.00   Median :  -1.2045   Median :-0.0185  
 Mean   :13801   Mean   :  20.522   Mean   :15854   Mean   : 65.45   Mean   : 65.69   Mean   :   0.2373   Mean   :    Inf  
 3rd Qu.:20685   3rd Qu.:  15.781   3rd Qu.:23574   3rd Qu.: 91.56   3rd Qu.: 92.00   3rd Qu.:   4.5861   3rd Qu.: 0.0898  
 Max.   :27388   Max.   :1114.329   Max.   :30757   Max.   :100.00   Max.   :100.00   Max.   : 100.0000   Max.   :    Inf  
                                                                                                          NA's   :350      
      TLID              BG_GEOID            CT_GEOID                  geometry    
 Min.   : 85694288   Min.   :2.503e+11   Min.   :2.503e+10   MULTIPOLYGON :24527  
 1st Qu.: 85701197   1st Qu.:2.503e+11   1st Qu.:2.503e+10   epsg:NA      :    0  
 Median : 85705981   Median :2.503e+11   Median :2.503e+10   +proj=lcc ...:    0  
 Mean   :130739389   Mean   :2.503e+11   Mean   :2.503e+10                        
 3rd Qu.: 85720558   3rd Qu.:2.503e+11   3rd Qu.:2.503e+10                        
 Max.   :645513578   Max.   :2.503e+11   Max.   :2.503e+10                        
                     NA's   :41          NA's   :71                               

Matching to Census geographies:

Loading Census geographies:

Map Census geographies:

# nicer plots:
boston_base <- get_map(location="Boston Latin Academy, Boston, MA",zoom=12, color="color",maptype="terrain",crop=T,source="google")
Error in data.frame(ll.lat = ll[1], ll.lon = ll[2], ur.lat = ur[1], ur.lon = ur[2]) : 
  arguments imply differing number of rows: 0, 1

rr (b1 <- b0 + geom_sf(data=boston_tracts,color = ,alpha=0.4,inherit.aes = F,guide=F,aes(fill=GEOID)) )

Error in UseMethod(\element_grob\) : 
  no applicable method for 'element_grob' applied to an object of class \NULL\

First match up the closest TLID

sum(!is.na(sw_pts_streets$TLID)) # got all of them!
[1] 24527

Visualize

Next, going to plot the sidewalk conditions at various geographies:

Street-level SCI changes

tmap_mode("view")
Error in tmap_mode("view") : could not find function "tmap_mode"

This map shows where sidewalk conditions got better between these two surveys (areas in green, with positive values of change in SCI) and where conditions got worse (red, or negative values of change in SCI). Looks like things improved in Jamaica Plain and East Bostn, but got worse in Dorchester and the northern edges of Charlestown.

Sidewalk conditions within tracts:

# join in CT of sidewalk segment:
boston_tracts <- st_transform(boston_tracts,st_crs(sw_pts_streets))
Error in st_crs(sw_pts_streets) : object 'sw_pts_streets' not found

Tract SCI changes

(b2 <- b0 + 
      geom_polygon(data=boston_tracts3,aes(x=long,y=lat,group=group,fill = mean_change_sci)) +
      theme(legend.key.width = unit(0.75, "cm"),legend.key.height = unit(2, "cm"),
            axis.line = NULL,panel.border = NULL,panel.grid = NULL) + 
            theme_bw()
 )
Error: object 'b0' not found

rr ggsave(b2,filename = /ct_mean_change_sci.png) # interactive plot: tmap_mode() tm_shape(boston_tracts2) + tm_fill(col = _change_sci,title = in SCI, palette=, n=20,midpoint=0, id = )

As with the segment-level map, this shows that conditions improved in JP and East Boston, but got worse in Mattapan/Dorchester and Charlestown.

Replicate this for BGs:

rr # join in BG of sidewalk segment: boston_bg <- st_transform(boston_bg,st_crs(sw_pts_streets)) sw_pts_bg <- st_join(x=sw_pts_streets,y=boston_bg,join=st_within,left=T)

bg_summ <- sw_pts_bg %>% as_tibble() %>% group_by(GEOID) %>% summarize(mean_sci_t1 = mean(SCI_t1,na.rm=T), mean_sci_t2 = mean(SCI_t2,na.rm=T), mean_change_sci = mean(SCI_change,na.rm=T))

boston_bg2 <- left_join(boston_bg,bg_summ,by=) # Output the BG-level sf data for other uses: save(boston_bg2,file = /boston_bg_sci.RData)

rr (b2 <- ggplot() + geom_sf(data=boston_bg2,aes(fill = mean_change_sci),alpha=1,inherit.aes = F,show.legend = ) )

BG SCI changes

rr ggsave(b2,filename = /bg_mean_change_sci.png) # interactive plot: tm_shape(boston_bg2) + tm_fill(col = _change_sci,title = in SCI, palette=, n=20,midpoint=0, id = )

This BG-level map corroborates the tract- and street-level visuals.

Adding census geographies back to crosswalk table

rr # matchtable2\(TLID <- sw_pts_streets\)TLID[match(matchtable2\(SWK_ID_t2,sw_pts_streets\)SWK_ID)] # matchtable2\(BG_GEOID <- sw_pts_bg\)GEOID[match(matchtable2\(SWK_ID_t2,sw_pts_bg\)SWK_ID)] # matchtable2\(CT_GEOID <- sw_pts_ct\)GEOID[match(matchtable2\(SWK_ID_t2,sw_pts_ct\)SWK_ID)] # write.csv(matchtable2,/SWK_matched_cwalk.csv,row.names = F) matchtable2 <- read.csv(/SWK_matched_cwalk.csv,stringsAsFactors = F)

Adding 311 data to analyses

First need to bring in 311 data from between the two sidewalk audits:

Matching 311 calls to census geographies:

rr sw_calls_pts\(SWK_ID_t2 <- NA for(i in 1:nrow(sw_calls)){ sw_calls_pts\)SWK_ID_t2[i] <- as.character( # match to closest sidewalk segment centroid sw_pts_streets\(SWK_ID[which.min(st_distance(sw_calls_pts[i,\geometry\], sw_pts_streets))] ) } sum(!is.na(sw_calls_pts\)SWK_ID_t2)) sw_calls_pts\(TLID <- matchtable2\)TLID[match(sw_calls_pts\(SWK_ID_t2,matchtable2\)SWK_ID_t2)] sw_calls_pts\(BG_GEOID <- matchtable2\)BG_GEOID[match(sw_calls_pts\(SWK_ID_t2,matchtable2\)SWK_ID_t2)] sw_calls_pts\(CT_GEOID <- matchtable2\)CT_GEOID[match(sw_calls_pts\(SWK_ID_t2,matchtable2\)SWK_ID_t2)] # save(sw_calls_pts,file = /sw_calls_geomatched.RData) load(file = /sw_calls_geomatched.RData)

Aggregating 311 data at geographic levels:

Street-level 311 visuals:

rr streets_summ_311 <- sw_calls_pts %>% as_tibble() %>% group_by(TLID) %>% summarize(n_calls = n()) %>% as.data.frame()

boston_streets_sci\(TLID <- as.numeric(boston_streets_sci\)TLID) boston_streets_sci <- left_join(boston_streets_sci,streets_summ_311,by=) boston_streets_sci\(n_calls[is.na(boston_streets_sci\)n_calls)] <- 0 boston_streets_sci\(nonzero_calls <- as.numeric(boston_streets_sci\)n_calls>0) boston_streets_sci\(log_calls <- log1p(boston_streets_sci\)n_calls) boston_streets_sci\(bin_calls <- cut(boston_streets_sci\)n_calls,breaks = c(-Inf,1,2,4,6,Inf), labels=c(,-2,-4,-6,+)) boston_streets_sci <- boston_streets_sci %>% mutate(change_sci_binned = cut(mean_change_sci, breaks=c(-Inf, -30, 30, Inf), labels=c(,,))) tm_shape(boston_streets_sci) + tm_lines(col = _calls,title.col = # of 311 Sidewalk Calls,lwd=2, palette=, n=5, id = )

Blockgroup 311 visuals:

Tract 311 visuals:

rr ct_summ_311 <- sw_calls_pts %>% as_tibble() %>% group_by(CT_GEOID) %>% summarize(n_calls = n()) %>% as.data.frame()

boston_tracts2\(GEOID <- as.numeric(boston_tracts2\)GEOID) boston_tracts2 <- left_join(boston_tracts2,ct_summ_311,by=c( = _GEOID)) boston_tracts2\(n_calls[is.na(boston_tracts2\)n_calls)] <- 0 boston_tracts2\(log_calls <- log1p(boston_tracts2\)n_calls) boston_tracts2\(bin_calls <- cut(boston_tracts2\)n_calls,breaks = c(-Inf,10,25,40,55,Inf), labels=c(-10,1-25,6-40,1-55,6+)) boston_tracts2 <- boston_tracts2 %>% mutate(change_sci_binned = cut(mean_change_sci, breaks=c(-Inf, -10, 10, Inf), labels=c(,,)))

tm_shape(boston_tracts2) + tm_fill(col = _calls,title = # of 311 Sidewalk Calls, palette=, n=5,midpoint=, id = )

How do 311 calls and SW quality differences match up at various aggregate levels?

Tract-level:

summary(lm((boston_tracts2$change_sci_binned=="Better") ~ boston_tracts2$n_calls*(boston_tracts2$mean_sci_t1>median(boston_tracts2$mean_sci_t1,na.rm=T)))) # differential impact of calls: all insig except less likely to get better if nicer area

Call:
lm(formula = (boston_tracts2$change_sci_binned == "Better") ~ 
    boston_tracts2$n_calls * (boston_tracts2$mean_sci_t1 > median(boston_tracts2$mean_sci_t1, 
        na.rm = T)))

Residuals:
     Min       1Q   Median       3Q      Max 
-0.40948 -0.31796 -0.06491 -0.04193  0.94358 

Coefficients:
                                                                                                       Estimate Std. Error
(Intercept)                                                                                            0.412433   0.066670
boston_tracts2$n_calls                                                                                -0.001476   0.001228
boston_tracts2$mean_sci_t1 > median(boston_tracts2$mean_sci_t1, na.rm = T)TRUE                        -0.336210   0.083694
boston_tracts2$n_calls:boston_tracts2$mean_sci_t1 > median(boston_tracts2$mean_sci_t1, na.rm = T)TRUE  0.001123   0.001349
                                                                                                      t value Pr(>|t|)    
(Intercept)                                                                                             6.186 4.32e-09 ***
boston_tracts2$n_calls                                                                                 -1.202    0.231    
boston_tracts2$mean_sci_t1 > median(boston_tracts2$mean_sci_t1, na.rm = T)TRUE                         -4.017 8.77e-05 ***
boston_tracts2$n_calls:boston_tracts2$mean_sci_t1 > median(boston_tracts2$mean_sci_t1, na.rm = T)TRUE   0.832    0.406    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3775 on 173 degrees of freedom
  (1 observation deleted due to missingness)
Multiple R-squared:  0.1403,    Adjusted R-squared:  0.1254 
F-statistic: 9.409 on 3 and 173 DF,  p-value: 8.565e-06

BG-level:

summary(lm((boston_bg2$change_sci_binned=="Better") ~ (boston_bg2$n_calls)*(boston_bg2$mean_sci_t1>median(boston_bg2$mean_sci_t1,na.rm=T)))) # differential impact of calls: nothing significant except nicer areas less likely to get better

Call:
lm(formula = (boston_bg2$change_sci_binned == "Better") ~ (boston_bg2$n_calls) * 
    (boston_bg2$mean_sci_t1 > median(boston_bg2$mean_sci_t1, 
        na.rm = T)))

Residuals:
     Min       1Q   Median       3Q      Max 
-0.35772 -0.34536 -0.04819 -0.03306  0.97703 

Coefficients:
                                                                                            Estimate Std. Error t value
(Intercept)                                                                                3.577e-01  2.479e-02  14.429
boston_bg2$n_calls                                                                        -6.178e-04  7.037e-04  -0.878
boston_bg2$mean_sci_t1 > median(boston_bg2$mean_sci_t1, na.rm = T)TRUE                    -3.051e-01  4.044e-02  -7.544
boston_bg2$n_calls:boston_bg2$mean_sci_t1 > median(boston_bg2$mean_sci_t1, na.rm = T)TRUE -1.257e-05  1.699e-03  -0.007
                                                                                          Pr(>|t|)    
(Intercept)                                                                                < 2e-16 ***
boston_bg2$n_calls                                                                           0.380    
boston_bg2$mean_sci_t1 > median(boston_bg2$mean_sci_t1, na.rm = T)TRUE                    1.88e-13 ***
boston_bg2$n_calls:boston_bg2$mean_sci_t1 > median(boston_bg2$mean_sci_t1, na.rm = T)TRUE    0.994    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3674 on 553 degrees of freedom
  (1 observation deleted due to missingness)
Multiple R-squared:  0.1487,    Adjusted R-squared:  0.1441 
F-statistic:  32.2 on 3 and 553 DF,  p-value: < 2.2e-16

street-level:

stats::cor(boston_streets_sci$mean_change_sci,y=boston_streets_sci$n_calls,use = "complete.obs")
Error in stats::cor(boston_streets_sci$mean_change_sci, y = boston_streets_sci$n_calls,  : 
  supply both 'x' and 'y' or a matrix-like 'x'

Visualizing correlation between calls and change in sidewalk conditions:

rr plot(log1p(boston_streets_sci\(n_calls),boston_streets_sci\)mean_change_sci,xlim=c(0,4),pch=16,col=,main=segment-level,ylab=in sidewalk conditions,xlab=of 311 calls) # lines(lowess(boston_streets_sci\(mean_change_sci ~ log1p(boston_streets_sci\)n_calls)),col=) lines(lowess(boston_streets_sci\(mean_change_sci[which(boston_streets_sci\)mean_sci_t1<median(boston_streets_sci\(mean_sci_t1,na.rm=T))] ~ log1p(boston_streets_sci\)n_calls[which(boston_streets_sci\(mean_sci_t1<median(boston_streets_sci\)mean_sci_t1,na.rm=T))])),col=,lwd=2) lines(lowess(boston_streets_sci\(mean_change_sci[which(boston_streets_sci\)mean_sci_t1>median(boston_streets_sci\(mean_sci_t1,na.rm=T))] ~ log1p(boston_streets_sci\)n_calls[which(boston_streets_sci\(mean_sci_t1>median(boston_streets_sci\)mean_sci_t1,na.rm=T))])),col=,lwd=2)

Nicer bivariate visuals:

rr (street_bivariate <- ggplot(boston_streets_sci) + geom_point(aes(x=n_calls,y=mean_change_sci),col=) + scale_x_continuous(of 311 calls(log scale),trans=10,limits=c(0.8,50),breaks=c(1,5,10,20,40)) + scale_y_continuous(in sidewalk conditions, limits=c(-100,100), breaks=seq(-100,100,50), labels=c(\n-100(Worse),-50,,0,\(Better)\n100\n\)) + geom_smooth(data=subset(boston_streets_sci,mean_sci_t1>median(boston_streets_sci\(mean_sci_t1,na.rm=T)), aes(x=n_calls,y=mean_change_sci),col=\blue\,lwd=1,method=\loess\,se=F) + geom_smooth(data=subset(boston_streets_sci,mean_sci_t1<=median(boston_streets_sci\)mean_sci_t1,na.rm=T)), aes(x=n_calls,y=mean_change_sci),col=,lwd=1,method=,se=F) + annotate(,x=0.8,y=15,label=street segments in 2012,col=,size=3,hjust=0) + annotate(,x=0.8,y=-15,label=street segments in 2012,col=,size=3,hjust=0) + theme_bw() )

# Saving visuals
ggsave(tract_bivariate,file="figures/calls_changeSCI_ct.pdf",height=4,width=6)
ggsave(bg_bivariate,file="figures/calls_changeSCI_bg.pdf",height=4,width=6)
ggsave(street_bivariate,file="figures/calls_changeSCI_streets.pdf",height=4,width=6)

Demographic analyses

Now lets bring in demographics to do something more than bivariate analyses:

summary(lm(mean_change_sci ~ log1p(n_calls)*B19013_001E, data = boston_tracts3)) # nothing sig

Call:
lm(formula = mean_change_sci ~ log1p(n_calls) * B19013_001E, 
    data = boston_tracts3)

Residuals:
    Min      1Q  Median      3Q     Max 
-26.193  -6.871  -1.547   3.899  38.867 

Coefficients:
                              Estimate  Std. Error t value Pr(>|t|)
(Intercept)                -0.18393946  7.27526449  -0.025    0.980
log1p(n_calls)              0.39596671  2.15971702   0.183    0.855
B19013_001E                 0.00006832  0.00010417   0.656    0.513
log1p(n_calls):B19013_001E -0.00001809  0.00002833  -0.639    0.524

Residual standard error: 12.23 on 165 degrees of freedom
  (9 observations deleted due to missingness)
Multiple R-squared:  0.004897,  Adjusted R-squared:  -0.0132 
F-statistic: 0.2707 on 3 and 165 DF,  p-value: 0.8465

The main lessons coming out of these analyses are that: (1) Whiter and higher income tracts and BGs were more likely to have improvement in sidewalk conditions between the two sidewalk conditions audits; and (2) In tracts and BGs with more white residents and with higher levels of education, the number of 311 calls doesn’t seem to correlate with improvements in sidewalk conditions, but in tracts and BGs with fewer white residents and lower levels of education, the number of 311 calls is positively correlated with improvements in sidewalk conditions.

Visualizing these dynamics:

# saving plots:
ggsave(tract_bivariate_inc,file="figures/calls_changeSCI_ct_inc.pdf",height=4,width=6)
ggsave(bg_bivariate_inc,file="figures/calls_changeSCI_bg_inc.pdf",height=4,width=6)
ggsave(bg_bivariate_inc_lm,file="figures/calls_changeSCI_bg_inc_lm.pdf",height=4,width=6)
LS0tCnRpdGxlOiAiU3RyZWV0Y2FzdGVyIFNpZGV3YWxrIEF1ZGl0cyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeShtYXB0b29scykgCmxpYnJhcnkocmdkYWwpIApsaWJyYXJ5KFJnb29nbGVNYXBzKSAjIGdvb2dsZW1hcHMgQVBJIHRvb2wKbGlicmFyeShjbGFzc0ludCkgCmxpYnJhcnkoUkNvbG9yQnJld2VyKSAKbGlicmFyeShnZ3Bsb3QyKTsgbGlicmFyeShnZ21hcCkgCmxpYnJhcnkobWFwcyk7bGlicmFyeShtYXBkYXRhKQpsaWJyYXJ5KHJnZW9zKQpsaWJyYXJ5KHRpZHljZW5zdXMpCmNlbnN1c19hcGlfa2V5KFN5cy5nZXRlbnYoIkNFTlNVU19BUElfS0VZIikpCmxpYnJhcnkodGlncmlzKSAjIHRvIHB1bGwgY2Vuc3VzIHNoYXBlZmlsZXMgZnJvbSB0aGUgd2ViIEFQSQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHNwKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkobHVicmlkYXRlKQojIGxpYnJhcnkodG1hcCkKbGlicmFyeShmb3JlaWduKQojIGxpYnJhcnkobmxtZSkKYGBgCgoKCkJyaW5nIGluIHRoZSBTVyBhdWRpdCBmaWxlIGZyb20gdGhlIEJBUkkgc2hhcmVkIEdvb2dsZSBEcml2ZSBhbmQgdGFrZSBhIGxvb2sgYXQgaXQuClRoaXMgc2hvdWxkIGJlIHRoZSBTaWRld2FsayBBdWRpdCBjb25kdWN0ZWQgaW4uLi4gd2hhdCB5ZWFyPwpgYGB7ciwgZWNobz1UUlVFfQpzd19wdHMgPC0gc3RfcmVhZChkc24gPSAifi9Hb29nbGUgRHJpdmUvQkFSSSBSZXNlYXJjaCBUZWFtIERhdGEgTGlicmFyeS9TdHJlZXRDYXN0ZXIvU2lkZXdhbGsgQ29uZGl0aW9ucyBUMS8iLGxheWVyPSJTaWRld2FsayBDZW50cm9pZHMiKQpzd19wb2x5IDwtIHN0X3JlYWQoZHNuID0gIn4vR29vZ2xlIERyaXZlL0JBUkkgUmVzZWFyY2ggVGVhbSBEYXRhIExpYnJhcnkvU3RyZWV0Q2FzdGVyL1NpZGV3YWxrIENvbmRpdGlvbnMgVDEvIixsYXllcj0iU1dLX0FOQUxZU0lTIikKc3VtbWFyeShzd19wdHMpCmBgYAoKCkJhc2ljIHN1bW1hcnkgc3RhdHM6CmBgYHtyfQpzdW1tYXJ5KHN3X3B0cyRUSU1FU1RBTVApCnN3X3B0cyRkYXRlMiA8LSBwYXJzZV9kYXRlX3RpbWUoeCA9IGFzLmNoYXJhY3Rlcihzd19wdHMkVElNRVNUQU1QKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVycz1jKCJtZFkiLCJZbWQgSE1TIiksIHRydW5jYXRlZCA9IDMpCnN1bW1hcnkoc3dfcHRzJGRhdGUyKSAjIGdvZXMgZnJvbSAyMDA4IHRocm91Z2ggMjAxMgojIHBkZigiZmlndXJlcy9hdWRpdDFfdGltZWxpbmUucGRmIixoZWlnaHQ9NCx3aWR0aD0xMCkKaGlzdChzd19wdHMkZGF0ZTIsYnJlYWtzID0gIm1vbnRocyIsbWFpbj0iVGltZWxpbmUgb2YgQXVkaXQgMSIseGxhYj0iRGF0ZSBvZiBBc3Nlc3NtZW50IikgIyBtb3N0bHkgaW4gdGhlIGVhcmx5IHBhcnQgb2YgMjAxMi4KIyBkZXYub2ZmKCkKKGRhdGVwbG90MSA8LSBnZ3Bsb3Qoc3dfcHRzKSArIAogICAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeD1kYXRlMikpICsgCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoIkRhdGUgb2YgQXNzZXNzbWVudCIsZGF0ZV9taW5vcl9icmVha3M9Im1vbnRocyIsZGF0ZV9sYWJlbHM9IiViICVZIikgKyAKICAgICAgdGhlbWVfYncoKSkKYGBgCgpgYGB7cn0KZ2dzYXZlKGRhdGVwbG90MSxmaWxlPSJmaWd1cmVzL3RpbWVsaW5lMS5wZGYiLGhlaWdodD00LHdpZHRoPTcpCiMgdGFibGUoc3dfcHRzJElOU1ApICMgbm90IHN1cmUgd2hhdCB0aGlzIG1lYW5zCiMgdGFibGUoc3dfcHRzJE5PVEVTKSAjIHRoaXMgbG9va3MgbW9yZSBxdWFsaXRhdGl2ZQpzdW1tYXJ5KHN3X3B0cyRTQ0kpICMgMC0xMDAgU2lkZXdhbGsgQ29uZGl0aW9uIEluZGV4CmBgYApTbywgaXQgbG9va3MgbGlrZSB0aGlzIGlzIHRoZSBxdWFsaXR5IG9mIHRoZSBzaWRld2Fsa3MKCk9rYXksIHRpbWUgdG8gYnJpbmcgaW4gdGhlIFNDSSByZXBvcnQgZnJvbSBUMjoKYGBge3J9CnN3X3BvbHlfdDIgPC0gc3RfcmVhZChkc24gPSAifi9Hb29nbGUgRHJpdmUvQkFSSSBSZXNlYXJjaCBUZWFtIERhdGEgTGlicmFyeS9TdHJlZXRDYXN0ZXIvU2lkZXdhbGsgQ29uZGl0aW9ucyBUMi8iLGxheWVyPSJTaWRld2Fsa3MiKQojIG5lZWQgdG8gcmVtb3ZlIGVtcHRpZXMgYmVmb3JlIGZpbmRpbmcgY2VudHJvaWRzOgpzd19wb2x5X3QyIDwtIHN3X3BvbHlfdDJbLXdoaWNoKGlzLm5hKHN0X2RpbWVuc2lvbihzd19wb2x5X3QyLE5BX2lmX2VtcHR5ID0gVCkpKSxdCiMgZmluZGluZyBjZW50cm9pZHMgdG8gdXNlIGFzIHBvaW50IGRhdGE6CnN3X3B0c190MiA8LSBzdF9jZW50cm9pZChzd19wb2x5X3QyKQpzdW1tYXJ5KHN3X3B0c190MikKYGBgCgpCYXNpYyBkZXNjcmlwdGl2ZXM6CgpgYGB7cn0Kc3VtbWFyeShzd19wb2x5X3QyJFNXS19JRCkgIyA1LWRpZ2l0IElEIG51bWJlcnMsIGJ1dCBub3QgdW5pcXVlPwpgYGAKCmBgYHtyfQpzdW1tYXJ5KHN3X3BvbHlfdDIkTmV3X1NDSSkgIyAwLTEwMCBTaWRld2FsayBDb25kaXRpb24gSW5kZXgKCmBgYAoKCiMgU3BhdGlhbCB2aXN1YWxzCgpQbG90IFNDSToKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQojIHBsb3Qoc3RfZ2VvbWV0cnkoc3dfcHRzKSxjb2w9IlNDSSIpCmdncGxvdChzd19wdHNbIlNDSSJdKSArIAogICAgICBnZW9tX3NmKGFlcyhjb2xvcj1TQ0ksZmlsbD1TQ0kpKQpgYGAKCk5ldyBkYXRhOgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KcGxvdChzd19wdHNfdDJbIk5ld19TQ0kiXSkKZ2dwbG90KHN3X3B0c190MlsiTmV3X1NDSSJdKSArIAogICAgICBnZW9tX3NmKGFlcyhjb2xvcj1OZXdfU0NJKSkKYGBgClRyeWluZyB0byBtYXRjaCB1cCBnZW9ncmFwaGllcyBhY3Jvc3MgdHdvIGF1ZGl0czoKYGBge3J9CnN3X3BvbHlfaWQxIDwtIHN3X3BvbHkgJT4lIAogICAgICBmaWx0ZXIoU1dLX0lEPT0iMSIpCnN3X3BvbHlfdDJfaWQxIDwtIHN3X3BvbHlfdDIgJT4lIAogICAgICBmaWx0ZXIoU1dLX0lEPT0iMSIpCiMgcGxvdChzd19wb2x5X2lkMVsiU0NJIl0pCnBsb3Qoc3RfZ2VvbWV0cnkoc3dfcG9seV9pZDEpKQoKYGBgCmBgYHtyfQojIHBsb3Qoc3dfcG9seV90Ml9pZDFbIk5ld19TQ0kiXSkKcGxvdChzdF9nZW9tZXRyeShzd19wb2x5X3QyX2lkMSkpCmBgYApTbyBubywgdGhvc2UgZG9uJ3QgbWF0Y2ggdXAuIFRoYXQncyBhIHBhaW4uCgpDaGVjayBpZiB0aGUgc2lkZXdhbGsgc2VnbWVudHMgbWF0Y2ggdXAgZnJvbSBUMSB0byBUMiBhdCBhbGwKYGBge3J9CnN0X2Nycyhzd19wb2x5KTsgc3RfY3JzKHN3X3BvbHlfdDIpCnN3X3BvbHlfdDIgPC0gc3RfdHJhbnNmb3JtKHN3X3BvbHlfdDIsc3RfY3JzKHN3X3BvbHkpKQojIHN3X3BvbHlfbWF0Y2ggPC0gc3RfZXF1YWxzX2V4YWN0KHN3X3BvbHksc3dfcG9seV90MixzcGFyc2U9VCxwYXI9MC4wMDEpCiMgYXBwbHkoc3dfcG9seV9tYXRjaCwxLGFueSkKIyBzdW0oYXBwbHkoWCA9IHN3X3BvbHlfbWF0Y2gsMSxGVU4gPSBmdW5jdGlvbih4KXtsZW5ndGgoeCk+MH0pKQojIHN3X3BvbHlfbWF0Y2ggPC0gc3RfY29udGFpbnMoc3dfcG9seSxzd19wb2x5X3QyLHNwYXJzZT1UKQojIHN3X3BvbHlfY29tcGFjdCA8LSBzd19wb2x5ICU+JQojICAgICAgIHNlbGVjdChTV0tfSUQsU0NJKSAlPiUKIyAgICAgICByZW5hbWUoU1dLX0lEX3QxID0gU1dLX0lELAojICAgICAgICAgICAgICBTQ0lfdDEgPSBTQ0kpCiMgc3dfcG9seV90Ml9tYXRjaGVkIDwtIHN0X2pvaW4oc3dfcG9seV90Mixzd19wb2x5X2NvbXBhY3Qsam9pbj1zdF8pCiMgbWVhbighaXMubmEoc3dfcG9seV90Ml9tYXRjaGVkJFNDSV90MSkpKjEwMCAjIG9ubHkgd29ya2VkIGZvciAwLjE0JQpgYGAKCkxldCdzIGxvb2sgYXQgc29tZSBzdWJzZXRzIHRvIHNlZSBob3cgdG8gbWF0Y2ggdGhlbSBzcGF0aWFsbHkKYGBge3J9CnN3X3BvbHlfdDIgPC0gc3RfdHJhbnNmb3JtKHN3X3BvbHlfdDIsc3RfY3JzKHN3X3BvbHkpKQoKc3dfcG9seV9jdG93biA8LSBzd19wb2x5ICU+JSAKICAgICAgZmlsdGVyKERJU1RSSUNUPT0iQ0hBUkxFU1RPV04iKQpzd19wb2x5X3QyX2N0b3duIDwtIHN3X3BvbHlfdDIgJT4lIAogICAgICBmaWx0ZXIoRElTVFJJQ1Q9PSJDSEFSTEVTVE9XTiIpCnBsb3Qoc3RfZ2VvbWV0cnkoc3dfcG9seV9jdG93bikpCnBsb3Qoc3RfZ2VvbWV0cnkoc3dfcG9seV90Ml9jdG93biksY29sPSJyZWQiLGFkZD1UKQojIGNvbnQxIDwtIHN0X2NvbnRhaW5zKHN3X3BvbHlfY3Rvd24sc3dfcG9seV90Ml9jdG93bixzcGFyc2U9VCkKIyBjb250MV9pbmQgPC0gd2hpY2goYXBwbHkoY29udDEsMSxhbnkpKSAjIGlkZW50aWZpZXMgd2hpY2ggb25lcyBpbiB0MSBjb250YWluIGFueSBpbiB0MgojICMgdmlzdWFsaXplIHNvbWUgb2YgdGhlc2U6CiMgcGxvdChzdF9nZW9tZXRyeShzdWJzZXQoc3dfcG9seV9jdG93bixhcHBseShjb250MSwxLGFueSkpKSkKIyBwbG90KHN0X2dlb21ldHJ5KHN3X3BvbHlfdDJfY3Rvd24pLGFkZD1ULGNvbD0icmVkIikKIyBwbG90KHN0X2dlb21ldHJ5KHN3X3BvbHlfY3Rvd24pLGFkZD1ULGNvbD0iYmx1ZSIpICMgdGhleSBkZWZpbml0ZWx5IG92ZXJsYXAgLSBzbyB0aGlzIGlzIHdlaXJkCmBgYAojIE1hdGNoaW5nIHNpZGV3YWxrcyBzZWdtZW50cyBhY3Jvc3Mgd2F2ZXMgb2YgYXVkaXRzIAojIyB0cnlpbmcgd2l0aCBjZW50cm9pZCBwb2ludHM6CmBgYHtyfQoKc3dfcHRzX3QyIDwtIHN0X3RyYW5zZm9ybShzd19wdHNfdDIsc3RfY3JzKHN3X3B0cykpCiMgZGlzdG1hdCA8LSBzdF9kaXN0YW5jZShzd19wdHMsc3dfcHRzX3QyKSAjIGluIGZ0IChVUykKIyBjbG9zZXN0IDwtIGFwcGx5KGRpc3RtYXQsMSxmdW5jdGlvbih4KXt3aGljaCh4PT1taW4oeCkpfSkKIyBjbG9zZXN0X2Rpc3QgPC0gYXBwbHkoZGlzdG1hdCwxLG1pbikgIyBkaXN0YW5jZSBpbiBmZWV0CiMgY2xvc2VzdFsxMDg3NV0KIyBwbG90KHN0X2dlb21ldHJ5KHN3X3BvbHlfdDJbYygxMzU4NCwyMjk0NyksIk5ld19TQ0kiXSkpICMgdGhlc2UgYXJlIGR1cGxpY2F0ZXMsIHRoYXQncyB3aHkhCiMgY2xvc2VzdFsxMDg3NV0gPC0gMTM1ODQgIyBtYW51YWwgZml4CiMgbWF0Y2h0YWJsZSA8LSB0aWJibGUoaW5kZXhfdDEgPSAxOmxlbmd0aCh1bmxpc3QoY2xvc2VzdCkpLAojICAgICAgICAgICAgICAgICAgICAgIGNsb3Nlc3RfaW5kZXggPSB1bmxpc3QoY2xvc2VzdCksCiMgICAgICAgICAgICAgICAgICAgICAgY2xvc2VzdF9kaXN0ID0gY2xvc2VzdF9kaXN0LAojICAgICAgICAgICAgICAgICAgICAgIFNXS19JRF90MSA9IHN3X3B0cyRTV0tfSUQpCiMgbWF0Y2h0YWJsZSRTV0tfSURfdDIgPC0gc3dfcHRzX3QyJFNXS19JRFttYXRjaHRhYmxlJGNsb3Nlc3RfaW5kZXhdCiMgc3VtbWFyeShtYXRjaHRhYmxlJGNsb3Nlc3RfZGlzdCkKIyBwbG90KHN0X2dlb21ldHJ5KHN3X3BvbHkgJT4lIGZpbHRlcihTV0tfSUQgJWluJSBtYXRjaHRhYmxlJFNXS19JRF90MVs4XSkpKSAjIHRoZXNlIHNob3VsZCBiZSBvdmVybGFwcGluZwojIHBsb3Qoc3RfZ2VvbWV0cnkoc3dfcG9seV90MiAlPiUgZmlsdGVyKFNXS19JRCAlaW4lIG1hdGNodGFibGUkU1dLX0lEX3QyWzhdKSksYWRkPVQsY29sPSJyZWQiKSAjIHNob3dzIHRoYXQgNDQgZnQgYXBhcnQgaW4gY2VudHJvaWRzIG5vdCBtdWNoCgpgYGAKV2hhdCBhYm91dCBsb29raW5nIGF0IHNvbWUgc2VnbWVudHMgdGhhdCBhcmUgZmFydGhlciBhcGFydD8KYGBge3J9CiMgbWF0Y2h0YWJsZSAlPiUgZmlsdGVyKGNsb3Nlc3RfZGlzdD4xMDAwKQpgYGAKCmBgYHtyfQojIHBsb3Qoc3RfZ2VvbWV0cnkoc3dfcG9seSAlPiUgZmlsdGVyKFNXS19JRCAlaW4lIG1hdGNodGFibGUkU1dLX0lEX3QxWzhdKSkpICMgdGhlc2Ugc2hvdWxkIGJlIG92ZXJsYXBwaW5nCiMgcGxvdChzdF9nZW9tZXRyeShzd19wb2x5X3QyICU+JSBmaWx0ZXIoU1dLX0lEICVpbiUgbWF0Y2h0YWJsZSRTV0tfSURfdDJbOF0pKSxhZGQ9VCxjb2w9InJlZCIpICMgc2hvd3MgdGhhdCA0NCBmdCBhcGFydCBpbiBjZW50cm9pZHMgbm90IG11Y2gKIyBwbG90KHN0X2dlb21ldHJ5KHN3X3BvbHkgJT4lIGZpbHRlcihTV0tfSUQgJWluJSBtYXRjaHRhYmxlJFNXS19JRF90MVsxMTgxXSkpKSAjIHRoZXNlIHNob3VsZCBiZSBvdmVybGFwcGluZwojIHBsb3Qoc3RfZ2VvbWV0cnkoc3dfcG9seV90MiAlPiUgZmlsdGVyKFNXS19JRCAlaW4lIG1hdGNodGFibGUkU1dLX0lEX3QyWzExODFdKSksYWRkPVQsY29sPSJyZWQiKSAjIHNob3dzIHRoYXQgZXZlbiAxMDQ3IGZ0IGFwYXJ0IGluIGNlbnRyb2lkcyBub3QgbXVjaCwgYW5kIHByb2JhYmx5IGEgY29ycmVjdCBtYXRjaCEKIyBgYGAKIyBgYGB7cn0KIyBwbG90KHN0X2dlb21ldHJ5KHN3X3BvbHkgJT4lIGZpbHRlcihTV0tfSUQgJWluJSBtYXRjaHRhYmxlJFNXS19JRF90MVsxMTgxOjExODddKSkpICMgdGhlc2Ugc2hvdWxkIGJlIG92ZXJsYXBwaW5nCiMgcGxvdChzdF9nZW9tZXRyeShzd19wb2x5X3QyICU+JSBmaWx0ZXIoU1dLX0lEICVpbiUgbWF0Y2h0YWJsZSRTV0tfSURfdDJbMTE4MToxMTg3XSkpLGFkZD1ULGNvbD0icmVkIikgIyBzaG93cyB0aGF0IGV2ZW4gMTA0NyBmdCBhcGFydCBpbiBjZW50cm9pZHMgbm90IG11Y2gsIGFuZCBwcm9iYWJseSBhIGNvcnJlY3QgbWF0Y2ghCmBgYApXaGF0IHRoaXMgc2VlbXMgdG8gYmUgc2hvd2luZyBpcyB0aGF0IGFjdHVhbGx5IHRoZXJlIGFyZSBqdXN0IHNvbWUgc2lkZXdhbGsgc2VnbWVudHMgdGhhdCBhcmUgbWlzc2luZyBpbiBXYXZlIDIgb2YgdGhlIFNDSSBzdXJ2ZXkuIFNob3dzIHdlIHNob3VsZCBhbHNvIGRvIHRoZSBtYXRjaGluZyBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uIC0gZS5nLiBmaW5kIGNsb3Nlc3Qgc2VnbWVudCB0byBlYWNoIFNXSyBpbiB3YXZlIDIgZnJvbSB3YXZlIDEuCgojIyBNYXRjaGluZyBpbiBvcHBvc2l0ZSBkaXJlY3Rpb24gKHdhdmUgMSB0byB3YXZlIDIpOgpgYGB7cn0KIyBkaXN0bWF0MiA8LSBzdF9kaXN0YW5jZShzd19wdHNfdDIsc3dfcHRzKSAjIGluIGZ0IChVUykKIyBjbG9zZXN0MiA8LSBhcHBseShkaXN0bWF0MiwxLGZ1bmN0aW9uKHgpe3doaWNoKHg9PW1pbih4KSl9KQojIGNsb3Nlc3RfZGlzdDIgPC0gYXBwbHkoZGlzdG1hdDIsMSxtaW4pICMgZGlzdGFuY2UgaW4gZmVldAojIG1hdGNodGFibGUyIDwtIHRpYmJsZShpbmRleF90MiA9IDE6bGVuZ3RoKHVubGlzdChjbG9zZXN0MikpLAojICAgICAgICAgICAgICAgICAgICAgIGNsb3Nlc3RfaW5kZXggPSB1bmxpc3QoY2xvc2VzdDIpLAojICAgICAgICAgICAgICAgICAgICAgIGNsb3Nlc3RfZGlzdCA9IGNsb3Nlc3RfZGlzdDIsCiMgICAgICAgICAgICAgICAgICAgICAgU1dLX0lEX3QyID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoc3dfcHRzX3QyJFNXS19JRCkpKQojIG1hdGNodGFibGUyJFNXS19JRF90MSA8LSBzd19wdHMkU1dLX0lEW21hdGNodGFibGUyJGNsb3Nlc3RfaW5kZXhdCiMgc3VtbWFyeShtYXRjaHRhYmxlMiRjbG9zZXN0X2Rpc3QpICMgbWF4aW11bSAxMTE0IGZ0LCB3aGljaCBpcyB0b3RhbGx5IGFsbG93YWJsZQpgYGAKTm93LCB0aW1lIHRvIG1hdGNoIGFuZCBjcmVhdGUgb3Zlci10aW1lIGNoYW5nZSBtZXRyaWNzCmBgYHtyfQojIG1hdGNodGFibGUyJFNDSV90MSA8LSBzd19wdHMkU0NJW21hdGNoKG1hdGNodGFibGUyJFNXS19JRF90MSxzd19wdHMkU1dLX0lEKV0KIyBtYXRjaHRhYmxlMiRTQ0lfdDIgPC0gc3dfcHRzX3QyJE5ld19TQ0lbbWF0Y2gobWF0Y2h0YWJsZTIkU1dLX0lEX3QyLHN3X3B0c190MiRTV0tfSUQpXQojIG1hdGNodGFibGUyIDwtIG1hdGNodGFibGUyICU+JQojICAgICAgIG11dGF0ZShTQ0lfY2hhbmdlID0gU0NJX3QyLVNDSV90MSwKIyAgICAgICAgICAgICAgU0NJX2NoYW5nZV9wZXJjID0gU0NJX2NoYW5nZS9TQ0lfdDEpCiMgc3VtbWFyeShtYXRjaHRhYmxlMikgIyBvbiBhdmVyYWdlLCBnb3QgYmV0dGVyIGJ5IDAuMSwgYnV0IG1lZGlhbiA9IC0xLjM5LiBwZXJjZW50IG1lc3NlZCB1cCBiL2Mgc29tZSBoYXZlIFNDST0wCmBgYApUaW1lIHRvIG1hdGNoIHRoZXNlIGRhdGEgYmFjayB0byB0aGUgcG9seWdvbnMKYGBge3J9CiMgd3JpdGUuY3N2KG1hdGNodGFibGUyLCJ0YWJsZXMvU1dLX21hdGNoZWRfY3dhbGsuY3N2Iixyb3cubmFtZXMgPSBGKQptYXRjaHRhYmxlMiA8LSByZWFkLmNzdigidGFibGVzL1NXS19tYXRjaGVkX2N3YWxrLmNzdiIsc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnN3X3BvbHlfdDIkU1dLX0lEID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoc3dfcG9seV90MiRTV0tfSUQpKQpzd19wb2x5X3QyIDwtIGxlZnRfam9pbihzd19wb2x5X3QyLG1hdGNodGFibGUyLGJ5PWMoIlNXS19JRCIgPSAiU1dLX0lEX3QyIikpCnN1bW1hcnkoc3dfcG9seV90MikKYGBgCgojIE1hdGNoaW5nIHRvIENlbnN1cyBnZW9ncmFwaGllczoKCiMjIExvYWRpbmcgQ2Vuc3VzIGdlb2dyYXBoaWVzOgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kb3B0aW9ucyh0aWdyaXNfY2xhc3MgPSAic2YiLHRpZ3Jpc191c2VfY2FjaGUgPSBUKQpiZyA8LSB0aWdyaXM6OmJsb2NrX2dyb3VwcygiTUEiLCJTdWZmb2xrIix5ZWFyID0gIjIwMTUiKQp0cmFjdHMgPC0gdGlncmlzOjp0cmFjdHMoIk1BIiwiU3VmZm9sayIseWVhciA9ICIyMDE1IikKc3RyZWV0cyA8LSB0aWdyaXM6OnJvYWRzKCJNQSIsIlN1ZmZvbGsiLHllYXIgPSAiMjAxNSIpCnRvd25zIDwtIHRpZ3Jpczo6Y291bnR5X3N1YmRpdmlzaW9ucygiTUEiLCJTdWZmb2xrIix5ZWFyID0gIjIwMTUiKQpib3N0b24gPC0gc3Vic2V0KHRvd25zLE5BTUUgPT0gIkJvc3RvbiIpCmJvc3Rvbl9iZyA8LSBiZ1t1bmxpc3Qoc3RfY29udGFpbnMoYm9zdG9uLGJnKSksXQpib3N0b25fdHJhY3RzIDwtIHRyYWN0c1t1bmxpc3Qoc3RfY29udGFpbnMoYm9zdG9uLHRyYWN0cykpLF0KIyBib3N0b25fc3RyZWV0cyA8LSBzdHJlZXRzW3VubGlzdChzdF9jb250YWlucyhib3N0b24sc3RyZWV0cykpLF0KYm9zdG9uX3N0cmVldHMgPC0gcmVhZE9HUihkc249cGFzdGUwKCIuLi9HZW9ncmFwaGljYWwgSW5mcmFzdHJ1Y3R1cmUvRGF0YS9HZW9ncmFwaGljYWwgSW5mcmFzdHJ1Y3R1cmUgMjAxOC9PdGhlci90bF8yMDE3XzI1MDI1X2FkZHJmZWF0LyIpLCBsYXllcj0idGxfMjAxN18yNTAyNV9hZGRyZmVhdCIpCmJvc3Rvbl9zdHJlZXRzIDwtIHN0X2FzX3NmKGJvc3Rvbl9zdHJlZXRzKQpgYGAKCiMjIE1hcCBDZW5zdXMgZ2VvZ3JhcGhpZXM6CgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdChzdF9nZW9tZXRyeShib3N0b25fc3RyZWV0cykpCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgbmljZXIgcGxvdHM6CmJvc3Rvbl9iYXNlIDwtIGdldF9tYXAobG9jYXRpb249IkJvc3RvbiBMYXRpbiBBY2FkZW15LCBCb3N0b24sIE1BIix6b29tPTEyLCBjb2xvcj0iY29sb3IiLG1hcHR5cGU9InRlcnJhaW4iLGNyb3A9VCxzb3VyY2U9Imdvb2dsZSIpCgpiMCA8LSBnZ21hcChib3N0b25fYmFzZSwgZXh0ZW50PSJkZXZpY2UiLGxlZ2VuZD0ibm9uZSIsbWFwcmFuZ2U9VCkKCihiMSA8LSBiMCArIAogICAgICBnZW9tX3NmKGRhdGE9Ym9zdG9uX2JnLGNvbG9yID0gImJsYWNrIixhbHBoYT0wLjQsaW5oZXJpdC5hZXM9RikpCgpgYGAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQooYjEgPC0gYjAgKyAKICAgICAgZ2VvbV9zZihkYXRhPWJvc3Rvbl90cmFjdHMsY29sb3IgPSAiYmxhY2siLGFscGhhPTAuNCxpbmhlcml0LmFlcyA9IEYsZ3VpZGU9RixhZXMoZmlsbD1HRU9JRCkpCiApCmBgYAoKIyMgRmlyc3QgbWF0Y2ggdXAgdGhlIGNsb3Nlc3QgVExJRAoKYGBge3J9CmJvc3Rvbl9zdHJlZXRzIDwtIHN0X3RyYW5zZm9ybShib3N0b25fc3RyZWV0cyxzdF9jcnMoc3dfcG9seV90MikpCnN3X3B0c190MiA8LSBzdF90cmFuc2Zvcm0oc3dfcHRzX3QyLHN0X2Nycyhib3N0b25fc3RyZWV0cykpCiMjIG5vbmUgb2YgdGhlc2UgbWV0aG9kcyBzZWVtIHRvIGJlIHdvcmtpbmcgZm9yIG1hdGNoaW5nIGJ5IGludGVyc2VjdGlvbiBvZiBwb2x5Z29ucyBhbmQgVEwgc2VnbWVudHM6CiMgc3dfcG9seV9zdHJlZXRzIDwtIHN0X2pvaW4oeD1zd19wb2x5X3QyLHk9Ym9zdG9uX3N0cmVldHMsam9pbj1zdF9pbnRlcnNlY3RzLGxlZnQ9VCkKIyBzd19wdHNfc3RyZWV0cyA8LSBzdF9qb2luKHg9c3dfcHRzX3QyLHk9Ym9zdG9uX3N0cmVldHMsam9pbj1zdF93aXRoaW4sbGVmdD1UKQojIHN0cmVldHNfam9pbmVkIDwtIHN0X2pvaW4oeD1ib3N0b25fc3RyZWV0cyx5PXN3X3BvbHlfdDIsam9pbj1zdF9pbnRlcnNlY3RzLGxlZnQ9RikKIyBzdW0oIWlzLm5hKHN3X3BvbHlfc3RyZWV0cyRUTElEKSkKIyMgaW5zdGVhZCwgZ29pbmcgdG8gZG8gYSBtaW4tZGlzdGFuY2UgbWF0Y2ggYmV0d2VlbiBjZW50cm9pZHMgb2YgU1cgYW5kIHRoZSBUTCBzdHJlZXQgc2VnbWVudHM6CiMgc3dfcHRzX3N0cmVldHMgPC0gc3dfcHRzX3QyCiMgc3dfcHRzX3N0cmVldHMkVExJRCA8LSBOQQojIGZvcihpIGluIDE6bnJvdyhzd19wdHNfc3RyZWV0cykpewojICAgICAgIHN3X3B0c19zdHJlZXRzJFRMSURbaV0gPC0gYXMuY2hhcmFjdGVyKGJvc3Rvbl9zdHJlZXRzJFRMSURbd2hpY2gubWluKHN0X2Rpc3RhbmNlKHN3X3B0c19zdHJlZXRzW2ksImdlb21ldHJ5Il0sIGJvc3Rvbl9zdHJlZXRzKSldKQojIH0KIyBzd19wdHNfc3RyZWV0cyRTV0tfSUQgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoc3dfcHRzX3N0cmVldHMkU1dLX0lEKSkKIyBzd19wdHNfc3RyZWV0cyA8LSBsZWZ0X2pvaW4oc3dfcHRzX3N0cmVldHMsbWF0Y2h0YWJsZTIsYnk9YygiU1dLX0lEIiA9ICJTV0tfSURfdDIiKSkKIyBzYXZlKHN3X3B0c19zdHJlZXRzLGZpbGUgPSAidGFibGVzL3N3X3B0c190Ml9zdHJlZXRzLlJEYXRhIikKbG9hZChmaWxlID0gInRhYmxlcy9zd19wdHNfdDJfc3RyZWV0cy5SRGF0YSIpCnN1bSghaXMubmEoc3dfcHRzX3N0cmVldHMkVExJRCkpICMgZ290IGFsbCBvZiB0aGVtIQpzdHJlZXRzX3N1bW0gPC0gc3dfcHRzX3N0cmVldHMgJT4lCiAgICAgIGdyb3VwX2J5KFRMSUQpICU+JQogICAgICBzdW1tYXJpemUobWVhbl9zY2lfdDEgPSBtZWFuKFNDSV90MSxuYS5ybT1UKSwKICAgICAgICAgICAgICAgIG1lYW5fc2NpX3QyID0gbWVhbihTQ0lfdDIsbmEucm09VCksCiAgICAgICAgICAgICAgICBtZWFuX2NoYW5nZV9zY2kgPSBtZWFuKFNDSV9jaGFuZ2UsbmEucm09VCkpCgpib3N0b25fc3RyZWV0c19zY2kgPC0gbGVmdF9qb2luKHg9Ym9zdG9uX3N0cmVldHMseT1hcy5kYXRhLmZyYW1lKHN0cmVldHNfc3VtbSksYnk9IlRMSUQiKSAlPiUKICAgICAgZmlsdGVyKCFpcy5uYShtZWFuX2NoYW5nZV9zY2kpKQojIHNhdmUoYm9zdG9uX3N0cmVldHNfc2NpLGZpbGUgPSAidGFibGVzL2Jvc3Rvbl9zdHJlZXRzX3NjaS5SRGF0YSIpCmxvYWQoZmlsZSA9ICJ0YWJsZXMvYm9zdG9uX3N0cmVldHNfc2NpLlJEYXRhIikKYGBgCgojIFZpc3VhbGl6ZQpOZXh0LCBnb2luZyB0byBwbG90IHRoZSBzaWRld2FsayBjb25kaXRpb25zIGF0IHZhcmlvdXMgZ2VvZ3JhcGhpZXM6CgpgYGB7cn0KYjIgPC0gZ2dwbG90KCkgKyAKICAgICAgZ2VvbV9zZihkYXRhPWJvc3Rvbl9zdHJlZXRzX3NjaSxhZXMoY29sb3IgPSBjdXRfaW50ZXJ2YWwobWVhbl9jaGFuZ2Vfc2NpLDEwKSksaW5oZXJpdC5hZXM9RixzaG93LmxlZ2VuZCA9ICJwb2x5Z29uIikgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJSZFlsR24iLG5hbWU9IkNoYW5nZSBpbiBTQ0kiKSArIAogICAgICAgIyB0aGVtZV9idygpICsgCiAgICAgICMgdGhlbWVfdm9pZCgpCiAgICAgICB0aGVtZShheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpLGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSxheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCkscGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSxwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICd0cmFuc3BhcmVudCcpLAogICAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCkscGxvdC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSkKICAKYGBgCgojIyMgU3RyZWV0LWxldmVsIFNDSSBjaGFuZ2VzCgpgYGB7cn0KZ2dzYXZlKGIyLGZpbGVuYW1lID0gImZpZ3VyZXMvdGxpZF9tZWFuX2NoYW5nZV9zY2kucG5nIikKIyBpbnRlcmFjdGl2ZSBwbG90Ogp0bWFwX21vZGUoInZpZXciKQp0bV9zaGFwZShib3N0b25fc3RyZWV0c19zY2kpICsgCiAgICAgIHRtX2xpbmVzKGNvbCA9ICJtZWFuX2NoYW5nZV9zY2kiLHRpdGxlLmNvbCA9ICJDaGFuZ2UgaW4gU0NJIixsd2Q9MiwKICAgICAgICAgICAgICAgcGFsZXR0ZT0iUmRZbEduIiwgbj0yMCxtaWRwb2ludD0wLAogICAgICAgICAgICAgIGlkID0gIlRMSUQiKQpgYGAKVGhpcyBtYXAgc2hvd3Mgd2hlcmUgc2lkZXdhbGsgY29uZGl0aW9ucyBnb3QgYmV0dGVyIGJldHdlZW4gdGhlc2UgdHdvIHN1cnZleXMgKGFyZWFzIGluIGdyZWVuLCB3aXRoIHBvc2l0aXZlIHZhbHVlcyBvZiBjaGFuZ2UgaW4gU0NJKSBhbmQgd2hlcmUgY29uZGl0aW9ucyBnb3Qgd29yc2UgKHJlZCwgb3IgbmVnYXRpdmUgdmFsdWVzIG9mIGNoYW5nZSBpbiBTQ0kpLiBMb29rcyBsaWtlIHRoaW5ncyBpbXByb3ZlZCBpbiBKYW1haWNhIFBsYWluIGFuZCBFYXN0IEJvc3RuLCBidXQgZ290IHdvcnNlIGluIERvcmNoZXN0ZXIgYW5kIHRoZSBub3J0aGVybiBlZGdlcyBvZiBDaGFybGVzdG93bi4KClNpZGV3YWxrIGNvbmRpdGlvbnMgd2l0aGluIHRyYWN0czoKCmBgYHtyfQojIGJyaW5nIFNDSSBkYXRhIGludG8gcG9pbnRzIGRhdGFzZXRzOgojIHN3X3B0c190MiRTV0tfSUQgPSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihzd19wdHNfdDIkU1dLX0lEKSkKIyBzd19wdHNfdDIgPC0gbGVmdF9qb2luKHN3X3B0c190MixtYXRjaHRhYmxlMixieT1jKCJTV0tfSUQiID0gIlNXS19JRF90MiIpKQoKIyBqb2luIGluIENUIG9mIHNpZGV3YWxrIHNlZ21lbnQ6CmJvc3Rvbl90cmFjdHMgPC0gc3RfdHJhbnNmb3JtKGJvc3Rvbl90cmFjdHMsc3RfY3JzKHN3X3B0c19zdHJlZXRzKSkKIyBzd19vdmVyIDwtIG92ZXIoYXMoc3dfcHRzLCJTcGF0aWFsIiksYXMoYm9zdG9uX3RyYWN0cywiU3BhdGlhbCIpKQpzd19wdHNfY3QgPC0gc3Rfam9pbih4PXN3X3B0c19zdHJlZXRzLHk9Ym9zdG9uX3RyYWN0cyxqb2luPXN0X3dpdGhpbixsZWZ0PVQpCgpjdF9zdW1tIDwtIHN3X3B0c19jdCAlPiUKICAgICAgYXNfdGliYmxlKCkgJT4lCiAgICAgIGdyb3VwX2J5KEdFT0lEKSAlPiUKICAgICAgc3VtbWFyaXplKG1lYW5fc2NpX3QxID0gbWVhbihTQ0lfdDEsbmEucm09VCksCiAgICAgICAgICAgICAgICBtZWFuX3NjaV90MiA9IG1lYW4oU0NJX3QyLG5hLnJtPVQpLAogICAgICAgICAgICAgICAgbWVhbl9jaGFuZ2Vfc2NpID0gbWVhbihTQ0lfY2hhbmdlLG5hLnJtPVQpKQogICAgICAKYm9zdG9uX3RyYWN0czIgPC0gbGVmdF9qb2luKGJvc3Rvbl90cmFjdHMsY3Rfc3VtbSxieT0iR0VPSUQiKQojIHNhdmUoYm9zdG9uX3RyYWN0czIsZmlsZSA9ICJ0YWJsZXMvYm9zdG9uX3RyYWN0c19zY2kuUkRhdGEiKQpsb2FkKGZpbGUgPSAidGFibGVzL2Jvc3Rvbl90cmFjdHNfc2NpLlJEYXRhIikKYGBgCgojIyMgVHJhY3QgU0NJIGNoYW5nZXMKCmBgYHtyfQpib3N0b25fdHJhY3RzMyA8LSBhcyhib3N0b25fdHJhY3RzMiwiU3BhdGlhbCIpCmJvc3Rvbl90cmFjdHMzQGRhdGEkaWQgPC0gcm93bmFtZXMoYm9zdG9uX3RyYWN0czNAZGF0YSkKYm9zdG9uX3RyYWN0czQgPC0gZm9ydGlmeShib3N0b25fdHJhY3RzMyxyZWdpb249ImlkIikgIyBzZXBhcmF0ZXMgcG9seWdvbnMgaW50byBpbmRpdmlkdWFsIHZlcnRpY2VzCmJvc3Rvbl90cmFjdHMzIDwtIG1lcmdlKGJvc3Rvbl90cmFjdHM0LGJvc3Rvbl90cmFjdHMzQGRhdGEsYnk9ImlkIikgIyBtZXJnZSBpbiBhbGwgdGhlIG90aGVyIHBvbHkgZGF0YSBmb3IgZWFjaAoKKGIyIDwtIGIwICsgCiAgICAgIGdlb21fcG9seWdvbihkYXRhPWJvc3Rvbl90cmFjdHMzLGFlcyh4PWxvbmcseT1sYXQsZ3JvdXA9Z3JvdXAsZmlsbCA9IG1lYW5fY2hhbmdlX3NjaSkpICsKICAgICAgdGhlbWUobGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC43NSwgImNtIiksbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDIsICJjbSIpLAogICAgICAgICAgICBheGlzLmxpbmUgPSBOVUxMLHBhbmVsLmJvcmRlciA9IE5VTEwscGFuZWwuZ3JpZCA9IE5VTEwpICsgCiAgICAgICAgICAgIHRoZW1lX2J3KCkKICkKYGBgCgpgYGB7cn0KZ2dzYXZlKGIyLGZpbGVuYW1lID0gImZpZ3VyZXMvY3RfbWVhbl9jaGFuZ2Vfc2NpLnBuZyIpCiMgaW50ZXJhY3RpdmUgcGxvdDoKdG1hcF9tb2RlKCJ2aWV3IikKdG1fc2hhcGUoYm9zdG9uX3RyYWN0czIpICsgCiAgICAgIHRtX2ZpbGwoY29sID0gIm1lYW5fY2hhbmdlX3NjaSIsdGl0bGUgPSAiQ2hhbmdlIGluIFNDSSIsCiAgICAgICAgICAgICAgIHBhbGV0dGU9IlJkWWxHbiIsIG49MjAsbWlkcG9pbnQ9MCwKICAgICAgICAgICAgICBpZCA9ICJUUkFDVENFIikKYGBgCkFzIHdpdGggdGhlIHNlZ21lbnQtbGV2ZWwgbWFwLCB0aGlzIHNob3dzIHRoYXQgY29uZGl0aW9ucyBpbXByb3ZlZCBpbiBKUCBhbmQgRWFzdCBCb3N0b24sIGJ1dCBnb3Qgd29yc2UgaW4gTWF0dGFwYW4vRG9yY2hlc3RlciBhbmQgQ2hhcmxlc3Rvd24uCgpSZXBsaWNhdGUgdGhpcyBmb3IgQkdzOgoKYGBge3J9CiMgam9pbiBpbiBCRyBvZiBzaWRld2FsayBzZWdtZW50Ogpib3N0b25fYmcgPC0gc3RfdHJhbnNmb3JtKGJvc3Rvbl9iZyxzdF9jcnMoc3dfcHRzX3N0cmVldHMpKQpzd19wdHNfYmcgPC0gc3Rfam9pbih4PXN3X3B0c19zdHJlZXRzLHk9Ym9zdG9uX2JnLGpvaW49c3Rfd2l0aGluLGxlZnQ9VCkKCmJnX3N1bW0gPC0gc3dfcHRzX2JnICU+JQogICAgICBhc190aWJibGUoKSAlPiUKICAgICAgZ3JvdXBfYnkoR0VPSUQpICU+JQogICAgICBzdW1tYXJpemUobWVhbl9zY2lfdDEgPSBtZWFuKFNDSV90MSxuYS5ybT1UKSwKICAgICAgICAgICAgICAgIG1lYW5fc2NpX3QyID0gbWVhbihTQ0lfdDIsbmEucm09VCksCiAgICAgICAgICAgICAgICBtZWFuX2NoYW5nZV9zY2kgPSBtZWFuKFNDSV9jaGFuZ2UsbmEucm09VCkpCiAgICAgIApib3N0b25fYmcyIDwtIGxlZnRfam9pbihib3N0b25fYmcsYmdfc3VtbSxieT0iR0VPSUQiKQojIE91dHB1dCB0aGUgQkctbGV2ZWwgc2YgZGF0YSBmb3Igb3RoZXIgdXNlczoKc2F2ZShib3N0b25fYmcyLGZpbGUgPSAidGFibGVzL2Jvc3Rvbl9iZ19zY2kuUkRhdGEiKQpgYGAKCgpgYGB7cn0KKGIyIDwtIGdncGxvdCgpICsgCiAgICAgIGdlb21fc2YoZGF0YT1ib3N0b25fYmcyLGFlcyhmaWxsID0gbWVhbl9jaGFuZ2Vfc2NpKSxhbHBoYT0xLGluaGVyaXQuYWVzID0gRixzaG93LmxlZ2VuZCA9ICJwb2x5Z29uIikgCiApCmBgYAojIyMgQkcgU0NJIGNoYW5nZXMKYGBge3J9Cmdnc2F2ZShiMixmaWxlbmFtZSA9ICJmaWd1cmVzL2JnX21lYW5fY2hhbmdlX3NjaS5wbmciKQojIGludGVyYWN0aXZlIHBsb3Q6CnRtX3NoYXBlKGJvc3Rvbl9iZzIpICsgCiAgICAgIHRtX2ZpbGwoY29sID0gIm1lYW5fY2hhbmdlX3NjaSIsdGl0bGUgPSAiQ2hhbmdlIGluIFNDSSIsCiAgICAgICAgICAgICAgIHBhbGV0dGU9IlJkWWxHbiIsIG49MjAsbWlkcG9pbnQ9MCwKICAgICAgICAgICAgICBpZCA9ICJHRU9JRCIpCmBgYApUaGlzIEJHLWxldmVsIG1hcCBjb3Jyb2JvcmF0ZXMgdGhlIHRyYWN0LSBhbmQgc3RyZWV0LWxldmVsIHZpc3VhbHMuCgojIyBBZGRpbmcgY2Vuc3VzIGdlb2dyYXBoaWVzIGJhY2sgdG8gY3Jvc3N3YWxrIHRhYmxlCmBgYHtyfQojIG1hdGNodGFibGUyJFRMSUQgPC0gc3dfcHRzX3N0cmVldHMkVExJRFttYXRjaChtYXRjaHRhYmxlMiRTV0tfSURfdDIsc3dfcHRzX3N0cmVldHMkU1dLX0lEKV0KIyBtYXRjaHRhYmxlMiRCR19HRU9JRCA8LSBzd19wdHNfYmckR0VPSURbbWF0Y2gobWF0Y2h0YWJsZTIkU1dLX0lEX3QyLHN3X3B0c19iZyRTV0tfSUQpXQojIG1hdGNodGFibGUyJENUX0dFT0lEIDwtIHN3X3B0c19jdCRHRU9JRFttYXRjaChtYXRjaHRhYmxlMiRTV0tfSURfdDIsc3dfcHRzX2N0JFNXS19JRCldCiMgd3JpdGUuY3N2KG1hdGNodGFibGUyLCJ0YWJsZXMvU1dLX21hdGNoZWRfY3dhbGsuY3N2Iixyb3cubmFtZXMgPSBGKQptYXRjaHRhYmxlMiA8LSByZWFkLmNzdigidGFibGVzL1NXS19tYXRjaGVkX2N3YWxrLmNzdiIsc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmBgYAoKIyBBZGRpbmcgMzExIGRhdGEgdG8gYW5hbHlzZXMKRmlyc3QgbmVlZCB0byBicmluZyBpbiAzMTEgZGF0YSBmcm9tIGJldHdlZW4gdGhlIHR3byBzaWRld2FsayBhdWRpdHM6CmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiMjIG9sZCBkYXRhIGF3IFNXLWxldmVsOgojIGRhdDMxMSA8LSByZWFkLmR0YSgiU2lkZXdhbGtzIGZvciBITE0uZHRhIikgIyB0aGVzZSBhcmVuJ3QgcmVhbGx5IGNhbGxzLi4uIHRoZXkgc2VlbSB0byBiZSBjYWxscyBhdCB0aGUgc2lkZXdhbGstdW5pdCBsZXZlbD8gbm8gZ2VvZ3JhcGhpYyBpbmZvIG90aGVyIHRoYW4gU1dLX0lELCBCR19JRCwgYW5kIENUX0lECiMgc3dfcHRzX3N0cmVldHMkY2FsbHNfb2xkIDwtIGRhdDMxMSRjYWxsc1ttYXRjaChzd19wdHNfc3RyZWV0cyRTV0tfSURfdDEsZGF0MzExJFNXS19JRCldCmRhdDMxMSA8LSByZWFkX2NzdigiLi4vMzExIENSTSBTZXJ2aWNlIFJlcXVlc3RzL0RhdGEvUmF3IEZpbGVzL2xhZ2FuMzExc2VydmljZXJlcXVlc3RzLmNzdiIpCnRhYmxlKGRhdDMxMSRSRUFTT04pCnRhYmxlKGRhdDMxMSRUWVBFKQpzd19jYWxscyA8LSBkYXQzMTEgJT4lCiAgICAgIGZpbHRlcihSRUFTT04gPT0iU2lkZXdhbGsgQ292ZXIgLyBNYW5ob2xlIiB8IAogICAgICAgICAgICAgICAgICAgVFlQRSAlaW4lIGMoIlNpZGV3YWxrIENvdmVyIC8gTWFuaG9sZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjICJHcm91bmQgTWFpbnRlbmFuY2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNpZGV3YWxrIFJlcGFpciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2lkZXdhbGsgUmVwYWlyIChJbnRlcm5hbCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNpZGV3YWxrIFJlcGFpciAoTWFrZSBTYWZlKSIpKSAlPiUKICAgICAgIyBUeXBlIExJS0UgJyVTaWRld2FsayUnIEFORCBUWVBFIE5vdCBMSUtFICclQ292ZXIlJyBBTkQgU291cmNlIH49ICdFbXBsb3llZSBHZW5lcmF0ZWQnIEFORCBTb3VyY2Ugfj0gJ0NpdHkgV29ya2VyIEFwcCc7KSAjIGZyb20gRGFuJ3MgU0FTIGNvZGU/CiAgICAgIGZpbHRlcihTb3VyY2UgIT0gIkVtcGxveWVlIEdlbmVyYXRlZCIgJiAKICAgICAgICAgICAgICAgICAgIFNvdXJjZSAhPSAiQ2l0eSBXb3JrZXIgQXBwIikgJT4lCiAgICAgIGZpbHRlcihMb2NhdGlvbiAhPSAiMTAwIENpdHkgSGFsbCBQbHogQm9zdG9uIE1BIDAyMTA4IiAmCiAgICAgICAgICAgICAgICAgICBMb2NhdGlvbiAhPSAiMSBDaXR5IEhhbGwgUGx6IEJvc3RvbiBNQSAwMjEwOCIpCiAgICAgIGZpbHRlcihvcGVuX2R0ID49IGFzLkRhdGUoIjIwMTItMDEtMDEiKSAmIG9wZW5fZHQgPCBhcy5EYXRlKCIyMDE1LTAxLTAxIikpICMgaW4gdGltZSB3aW5kb3cKc3dfY2FsbHMgJT4lIGdyb3VwX2J5KExvY2F0aW9uKSAlPiUgc3VtbWFyaXplKHN1bWNhbGxzID0gbigpKSAlPiUgYXJyYW5nZShkZXNjKHN1bWNhbGxzKSkKCnN3X2NhbGxzX3B0cyA8LSBzdF9hc19zZihzd19jYWxscyxjb29yZHM9YygiTG9uZ2l0dWRlIiwiTGF0aXR1ZGUiKSxjcnM9Iitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0IikKc3dfY2FsbHNfcHRzIDwtIHN0X3RyYW5zZm9ybShzd19jYWxsc19wdHMsc3RfY3JzKHN3X3B0c19zdHJlZXRzKSkKYGBgCgojIyBNYXRjaGluZyAzMTEgY2FsbHMgdG8gY2Vuc3VzIGdlb2dyYXBoaWVzOgpgYGB7cn0Kc3dfY2FsbHNfcHRzJFNXS19JRF90MiA8LSBOQQpmb3IoaSBpbiAxOm5yb3coc3dfY2FsbHMpKXsKICAgICAgc3dfY2FsbHNfcHRzJFNXS19JRF90MltpXSA8LSBhcy5jaGFyYWN0ZXIoICMgbWF0Y2ggdG8gY2xvc2VzdCBzaWRld2FsayBzZWdtZW50IGNlbnRyb2lkCiAgICAgICAgICAgIHN3X3B0c19zdHJlZXRzJFNXS19JRFt3aGljaC5taW4oc3RfZGlzdGFuY2Uoc3dfY2FsbHNfcHRzW2ksImdlb21ldHJ5Il0sIHN3X3B0c19zdHJlZXRzKSldCiAgICAgICAgICAgICkKfQpzdW0oIWlzLm5hKHN3X2NhbGxzX3B0cyRTV0tfSURfdDIpKQpzd19jYWxsc19wdHMkVExJRCA8LSBtYXRjaHRhYmxlMiRUTElEW21hdGNoKHN3X2NhbGxzX3B0cyRTV0tfSURfdDIsbWF0Y2h0YWJsZTIkU1dLX0lEX3QyKV0Kc3dfY2FsbHNfcHRzJEJHX0dFT0lEIDwtIG1hdGNodGFibGUyJEJHX0dFT0lEW21hdGNoKHN3X2NhbGxzX3B0cyRTV0tfSURfdDIsbWF0Y2h0YWJsZTIkU1dLX0lEX3QyKV0Kc3dfY2FsbHNfcHRzJENUX0dFT0lEIDwtIG1hdGNodGFibGUyJENUX0dFT0lEW21hdGNoKHN3X2NhbGxzX3B0cyRTV0tfSURfdDIsbWF0Y2h0YWJsZTIkU1dLX0lEX3QyKV0KIyBzYXZlKHN3X2NhbGxzX3B0cyxmaWxlID0gInRhYmxlcy9zd19jYWxsc19nZW9tYXRjaGVkLlJEYXRhIikKbG9hZChmaWxlID0gInRhYmxlcy9zd19jYWxsc19nZW9tYXRjaGVkLlJEYXRhIikKYGBgCgojIyBBZ2dyZWdhdGluZyAzMTEgZGF0YSBhdCBnZW9ncmFwaGljIGxldmVsczoKIyMjIFN0cmVldC1sZXZlbCAzMTEgdmlzdWFsczoKCmBgYHtyfQpzdHJlZXRzX3N1bW1fMzExIDwtIHN3X2NhbGxzX3B0cyAlPiUKICAgICAgYXNfdGliYmxlKCkgJT4lCiAgICAgIGdyb3VwX2J5KFRMSUQpICU+JQogICAgICBzdW1tYXJpemUobl9jYWxscyA9IG4oKSkgJT4lCiAgICAgIGFzLmRhdGEuZnJhbWUoKQoKYm9zdG9uX3N0cmVldHNfc2NpJFRMSUQgPC0gYXMubnVtZXJpYyhib3N0b25fc3RyZWV0c19zY2kkVExJRCkKYm9zdG9uX3N0cmVldHNfc2NpIDwtIGxlZnRfam9pbihib3N0b25fc3RyZWV0c19zY2ksc3RyZWV0c19zdW1tXzMxMSxieT0iVExJRCIpCmJvc3Rvbl9zdHJlZXRzX3NjaSRuX2NhbGxzW2lzLm5hKGJvc3Rvbl9zdHJlZXRzX3NjaSRuX2NhbGxzKV0gPC0gMApib3N0b25fc3RyZWV0c19zY2kkbm9uemVyb19jYWxscyA8LSBhcy5udW1lcmljKGJvc3Rvbl9zdHJlZXRzX3NjaSRuX2NhbGxzPjApCmJvc3Rvbl9zdHJlZXRzX3NjaSRsb2dfY2FsbHMgPC0gbG9nMXAoYm9zdG9uX3N0cmVldHNfc2NpJG5fY2FsbHMpCmJvc3Rvbl9zdHJlZXRzX3NjaSRiaW5fY2FsbHMgPC0gY3V0KGJvc3Rvbl9zdHJlZXRzX3NjaSRuX2NhbGxzLGJyZWFrcyA9IGMoLUluZiwxLDIsNCw2LEluZiksIGxhYmVscz1jKCIwIiwiMS0yIiwiMi00IiwiNC02IiwiNisiKSkKYm9zdG9uX3N0cmVldHNfc2NpIDwtIGJvc3Rvbl9zdHJlZXRzX3NjaSAlPiUKICAgICAgbXV0YXRlKGNoYW5nZV9zY2lfYmlubmVkID0gY3V0KG1lYW5fY2hhbmdlX3NjaSwgYnJlYWtzPWMoLUluZiwgLTMwLCAzMCwgSW5mKSwgbGFiZWxzPWMoIldvcnNlIiwiU2ltaWxhciIsIkJldHRlciIpKSkKdG1fc2hhcGUoYm9zdG9uX3N0cmVldHNfc2NpKSArIAogICAgICB0bV9saW5lcyhjb2wgPSAiYmluX2NhbGxzIix0aXRsZS5jb2wgPSAiIyBvZiAzMTEgU2lkZXdhbGsgQ2FsbHMiLGx3ZD0yLAogICAgICAgICAgICAgICBwYWxldHRlPSJZbEduIiwgbj01LAogICAgICAgICAgICAgIGlkID0gIlRMSUQiKQpgYGAKCiMjIyBCbG9ja2dyb3VwIDMxMSB2aXN1YWxzOgpgYGB7cn0KYmdfc3VtbV8zMTEgPC0gc3dfY2FsbHNfcHRzICU+JQogICAgICBhc190aWJibGUoKSAlPiUKICAgICAgZ3JvdXBfYnkoQkdfR0VPSUQpICU+JQogICAgICBzdW1tYXJpemUobl9jYWxscyA9IG4oKSkgJT4lCiAgICAgIGFzLmRhdGEuZnJhbWUoKQoKYm9zdG9uX2JnMiRHRU9JRCA8LSBhcy5udW1lcmljKGJvc3Rvbl9iZzIkR0VPSUQpCmJvc3Rvbl9iZzIgPC0gbGVmdF9qb2luKGJvc3Rvbl9iZzIsYmdfc3VtbV8zMTEsYnk9YygiR0VPSUQiID0gIkJHX0dFT0lEIikpCmJvc3Rvbl9iZzIkbl9jYWxsc1tpcy5uYShib3N0b25fYmcyJG5fY2FsbHMpXSA8LSAwCmJvc3Rvbl9iZzIkbG9nX2NhbGxzIDwtIGxvZzFwKGJvc3Rvbl9iZzIkbl9jYWxscykKYm9zdG9uX2JnMiRiaW5fY2FsbHMgPC0gY3V0KGJvc3Rvbl9iZzIkbl9jYWxscyxicmVha3MgPSBjKC1JbmYsMyw2LDEyLDI0LEluZiksIGxhYmVscz1jKCIwLTMiLCI0LTYiLCI3LTEyIiwiMTMtMjQiLCIyNSsiKSkKYm9zdG9uX2JnMiA8LSBib3N0b25fYmcyICU+JQogICAgICBtdXRhdGUoY2hhbmdlX3NjaV9iaW5uZWQgPSBjdXQobWVhbl9jaGFuZ2Vfc2NpLCBicmVha3M9YygtSW5mLCAtMTAsIDEwLCBJbmYpLCBsYWJlbHM9YygiV29yc2UiLCJTaW1pbGFyIiwiQmV0dGVyIikpKQp0bV9zaGFwZShib3N0b25fYmcyKSArIAogICAgICB0bV9maWxsKGNvbCA9ICJiaW5fY2FsbHMiLHRpdGxlID0gIiMgb2YgMzExIFNpZGV3YWxrIENhbGxzIiwKICAgICAgICAgICAgICAgcGFsZXR0ZT0iWWxHbiIsIG49NSwKICAgICAgICAgICAgICBpZCA9ICJHRU9JRCIpCmBgYAojIyMgVHJhY3QgMzExIHZpc3VhbHM6CgpgYGB7cn0KY3Rfc3VtbV8zMTEgPC0gc3dfY2FsbHNfcHRzICU+JQogICAgICBhc190aWJibGUoKSAlPiUKICAgICAgZ3JvdXBfYnkoQ1RfR0VPSUQpICU+JQogICAgICBzdW1tYXJpemUobl9jYWxscyA9IG4oKSkgJT4lCiAgICAgIGFzLmRhdGEuZnJhbWUoKQoKYm9zdG9uX3RyYWN0czIkR0VPSUQgPC0gYXMubnVtZXJpYyhib3N0b25fdHJhY3RzMiRHRU9JRCkKYm9zdG9uX3RyYWN0czIgPC0gbGVmdF9qb2luKGJvc3Rvbl90cmFjdHMyLGN0X3N1bW1fMzExLGJ5PWMoIkdFT0lEIiA9ICJDVF9HRU9JRCIpKQpib3N0b25fdHJhY3RzMiRuX2NhbGxzW2lzLm5hKGJvc3Rvbl90cmFjdHMyJG5fY2FsbHMpXSA8LSAwCmJvc3Rvbl90cmFjdHMyJGxvZ19jYWxscyA8LSBsb2cxcChib3N0b25fdHJhY3RzMiRuX2NhbGxzKQpib3N0b25fdHJhY3RzMiRiaW5fY2FsbHMgPC0gY3V0KGJvc3Rvbl90cmFjdHMyJG5fY2FsbHMsYnJlYWtzID0gYygtSW5mLDEwLDI1LDQwLDU1LEluZiksIGxhYmVscz1jKCIwLTEwIiwiMTEtMjUiLCIyNi00MCIsIjQxLTU1IiwiNTYrIikpCmJvc3Rvbl90cmFjdHMyIDwtIGJvc3Rvbl90cmFjdHMyICU+JQogICAgICBtdXRhdGUoY2hhbmdlX3NjaV9iaW5uZWQgPSBjdXQobWVhbl9jaGFuZ2Vfc2NpLCBicmVha3M9YygtSW5mLCAtMTAsIDEwLCBJbmYpLCBsYWJlbHM9YygiV29yc2UiLCJTaW1pbGFyIiwiQmV0dGVyIikpKQoKdG1fc2hhcGUoYm9zdG9uX3RyYWN0czIpICsgCiAgICAgIHRtX2ZpbGwoY29sID0gImJpbl9jYWxscyIsdGl0bGUgPSAiIyBvZiAzMTEgU2lkZXdhbGsgQ2FsbHMiLAogICAgICAgICAgICAgICBwYWxldHRlPSJZbEduIiwgbj01LG1pZHBvaW50PSwKICAgICAgICAgICAgICBpZCA9ICJUUkFDVENFIikKYGBgCgojIyBIb3cgZG8gMzExIGNhbGxzIGFuZCBTVyBxdWFsaXR5IGRpZmZlcmVuY2VzIG1hdGNoIHVwIGF0IHZhcmlvdXMgYWdncmVnYXRlIGxldmVscz8KVHJhY3QtbGV2ZWw6CmBgYHtyfQpzdGF0czo6Y29yKGJvc3Rvbl90cmFjdHMyJG1lYW5fY2hhbmdlX3NjaSx5PWJvc3Rvbl90cmFjdHMyJG5fY2FsbHMsdXNlID0gImNvbXBsZXRlLm9icyIpCnN0YXRzOjpjb3IoYm9zdG9uX3RyYWN0czIkbWVhbl9jaGFuZ2Vfc2NpLHk9bG9nMXAoYm9zdG9uX3RyYWN0czIkbl9jYWxscyksdXNlID0gImNvbXBsZXRlLm9icyIpCnN1bW1hcnkobG0oYm9zdG9uX3RyYWN0czIkbWVhbl9jaGFuZ2Vfc2NpIH4gYm9zdG9uX3RyYWN0czIkbl9jYWxscykpICMgbmVnLCBpbnNpZwpzdW1tYXJ5KGxtKChib3N0b25fdHJhY3RzMiRjaGFuZ2Vfc2NpX2Jpbm5lZD09IkJldHRlciIpIH4gbG9nMXAoYm9zdG9uX3RyYWN0czIkbl9jYWxscykpKSAjIG5lZywgc2lnbmlmaWNhbnQKc3VtbWFyeShsbSgoYm9zdG9uX3RyYWN0czIkY2hhbmdlX3NjaV9iaW5uZWQ9PSJCZXR0ZXIiKSB+IGJvc3Rvbl90cmFjdHMyJG5fY2FsbHMqKGJvc3Rvbl90cmFjdHMyJG1lYW5fc2NpX3QxPm1lZGlhbihib3N0b25fdHJhY3RzMiRtZWFuX3NjaV90MSxuYS5ybT1UKSkpKSAjIGRpZmZlcmVudGlhbCBpbXBhY3Qgb2YgY2FsbHM6IGFsbCBpbnNpZyBleGNlcHQgbGVzcyBsaWtlbHkgdG8gZ2V0IGJldHRlciBpZiBuaWNlciBhcmVhCgpgYGAKCkJHLWxldmVsOgpgYGB7cn0Kc3RhdHM6OmNvcihib3N0b25fYmcyJG1lYW5fY2hhbmdlX3NjaSx5PWJvc3Rvbl9iZzIkbl9jYWxscyx1c2UgPSAiY29tcGxldGUub2JzIikgIyBwb3NpdGl2ZQpzdGF0czo6Y29yKGJvc3Rvbl9iZzIkbWVhbl9jaGFuZ2Vfc2NpLHk9bG9nMXAoYm9zdG9uX2JnMiRuX2NhbGxzKSx1c2UgPSAiY29tcGxldGUub2JzIikgIyBuZWcKIyBzdW1tYXJ5KGxtKGJvc3Rvbl9iZzIkbWVhbl9jaGFuZ2Vfc2NpIH4gKGJvc3Rvbl9iZzIkbl9jYWxscz4wKSkpCnN1bW1hcnkobG0oKGJvc3Rvbl9iZzIkY2hhbmdlX3NjaV9iaW5uZWQ9PSJCZXR0ZXIiKSB+IGxvZzFwKGJvc3Rvbl9iZzIkbl9jYWxscykpKSAjIG5lZywgaW5zaWcKc3VtbWFyeShsbSgoYm9zdG9uX2JnMiRjaGFuZ2Vfc2NpX2Jpbm5lZD09IkJldHRlciIpIH4gKGJvc3Rvbl9iZzIkbl9jYWxscykqKGJvc3Rvbl9iZzIkbWVhbl9zY2lfdDE+bWVkaWFuKGJvc3Rvbl9iZzIkbWVhbl9zY2lfdDEsbmEucm09VCkpKSkgIyBkaWZmZXJlbnRpYWwgaW1wYWN0IG9mIGNhbGxzOiBub3RoaW5nIHNpZ25pZmljYW50IGV4Y2VwdCBuaWNlciBhcmVhcyBsZXNzIGxpa2VseSB0byBnZXQgYmV0dGVyCmBgYAoKc3RyZWV0LWxldmVsOgpgYGB7cn0Kc3RhdHM6OmNvcihib3N0b25fc3RyZWV0c19zY2kkbWVhbl9jaGFuZ2Vfc2NpLHk9Ym9zdG9uX3N0cmVldHNfc2NpJG5fY2FsbHMsdXNlID0gImNvbXBsZXRlLm9icyIpCnN0YXRzOjpjb3IoYm9zdG9uX3N0cmVldHNfc2NpJG1lYW5fY2hhbmdlX3NjaSx5PWxvZzFwKGJvc3Rvbl9zdHJlZXRzX3NjaSRuX2NhbGxzKSx1c2UgPSAiY29tcGxldGUub2JzIikKc3VtbWFyeShsbShib3N0b25fc3RyZWV0c19zY2kkbWVhbl9jaGFuZ2Vfc2NpIH4gKGJvc3Rvbl9zdHJlZXRzX3NjaSRuX2NhbGxzPjApKSkKc3VtbWFyeShsbShib3N0b25fc3RyZWV0c19zY2kkbWVhbl9jaGFuZ2Vfc2NpIH4gbG9nMXAoYm9zdG9uX3N0cmVldHNfc2NpJG5fY2FsbHMpKSkKc3VtbWFyeShsbSgoYm9zdG9uX3N0cmVldHNfc2NpJGNoYW5nZV9zY2k9PSJCZXR0ZXIiKSB+IGxvZzFwKGJvc3Rvbl9zdHJlZXRzX3NjaSRuX2NhbGxzKSkpICMgbmVnYXRpdmUsIGluc2lnCnN1bW1hcnkobG0oKGJvc3Rvbl9zdHJlZXRzX3NjaSRjaGFuZ2Vfc2NpPT0iQmV0dGVyIikgfiBib3N0b25fc3RyZWV0c19zY2kkbl9jYWxscyooYm9zdG9uX3N0cmVldHNfc2NpJG1lYW5fc2NpX3QxPm1lZGlhbihib3N0b25fc3RyZWV0c19zY2kkbWVhbl9zY2lfdDEpKSkpICMgZGlmZmVyZW50aWFsIGltcGFjdCBvZiBjYWxsczogbm90aGluZyBzaWcgZXhjZXB0IG5pY2VyIGFyZWFzIGxlc3MgbGlrZWx5IHRvIGdldCBiZXR0ZXIKYGBgCgojIFZpc3VhbGl6aW5nIGNvcnJlbGF0aW9uIGJldHdlZW4gY2FsbHMgYW5kIGNoYW5nZSBpbiBzaWRld2FsayBjb25kaXRpb25zOgpgYGB7cn0KcGxvdChsb2cxcChib3N0b25fc3RyZWV0c19zY2kkbl9jYWxscyksYm9zdG9uX3N0cmVldHNfc2NpJG1lYW5fY2hhbmdlX3NjaSx4bGltPWMoMCw0KSxwY2g9MTYsY29sPSJncmV5IixtYWluPSJTdHJlZXQgc2VnbWVudC1sZXZlbCIseWxhYj0iQ2hhbmdlIGluIHNpZGV3YWxrIGNvbmRpdGlvbnMiLHhsYWI9Ik51bWJlciBvZiAzMTEgY2FsbHMiKQojIGxpbmVzKGxvd2Vzcyhib3N0b25fc3RyZWV0c19zY2kkbWVhbl9jaGFuZ2Vfc2NpIH4gbG9nMXAoYm9zdG9uX3N0cmVldHNfc2NpJG5fY2FsbHMpKSxjb2w9InJlZCIpCmxpbmVzKGxvd2Vzcyhib3N0b25fc3RyZWV0c19zY2kkbWVhbl9jaGFuZ2Vfc2NpW3doaWNoKGJvc3Rvbl9zdHJlZXRzX3NjaSRtZWFuX3NjaV90MTxtZWRpYW4oYm9zdG9uX3N0cmVldHNfc2NpJG1lYW5fc2NpX3QxLG5hLnJtPVQpKV0gfiBsb2cxcChib3N0b25fc3RyZWV0c19zY2kkbl9jYWxsc1t3aGljaChib3N0b25fc3RyZWV0c19zY2kkbWVhbl9zY2lfdDE8bWVkaWFuKGJvc3Rvbl9zdHJlZXRzX3NjaSRtZWFuX3NjaV90MSxuYS5ybT1UKSldKSksY29sPSJyZWQiLGx3ZD0yKQpsaW5lcyhsb3dlc3MoYm9zdG9uX3N0cmVldHNfc2NpJG1lYW5fY2hhbmdlX3NjaVt3aGljaChib3N0b25fc3RyZWV0c19zY2kkbWVhbl9zY2lfdDE+bWVkaWFuKGJvc3Rvbl9zdHJlZXRzX3NjaSRtZWFuX3NjaV90MSxuYS5ybT1UKSldIH4gbG9nMXAoYm9zdG9uX3N0cmVldHNfc2NpJG5fY2FsbHNbd2hpY2goYm9zdG9uX3N0cmVldHNfc2NpJG1lYW5fc2NpX3QxPm1lZGlhbihib3N0b25fc3RyZWV0c19zY2kkbWVhbl9zY2lfdDEsbmEucm09VCkpXSkpLGNvbD0iYmx1ZSIsbHdkPTIpCmBgYApgYGB7cn0KcGxvdChsb2cxcChib3N0b25fYmcyJG5fY2FsbHMpLGJvc3Rvbl9iZzIkbWVhbl9jaGFuZ2Vfc2NpLHhsaW09YygwLDUpLHBjaD0xNixjb2w9ImdyZXkiLG1haW49IkJsb2NrZ3JvdXAtbGV2ZWwiLHlsYWI9IkNoYW5nZSBpbiBzaWRld2FsayBjb25kaXRpb25zIix4bGFiPSJOdW1iZXIgb2YgMzExIGNhbGxzIikKIyBsaW5lcyhsb3dlc3MoYm9zdG9uX2JnMiRtZWFuX2NoYW5nZV9zY2kgfiBsb2cxcChib3N0b25fYmcyJG5fY2FsbHMpKSxjb2w9InJlZCIpCmxpbmVzKGxvd2Vzcyhib3N0b25fYmcyJG1lYW5fY2hhbmdlX3NjaVt3aGljaChib3N0b25fYmcyJG1lYW5fc2NpX3QxPm1lZGlhbihib3N0b25fYmcyJG1lYW5fc2NpX3QxLG5hLnJtPVQpKV0gfiBsb2cxcChib3N0b25fYmcyJG5fY2FsbHNbd2hpY2goYm9zdG9uX2JnMiRtZWFuX3NjaV90MT5tZWRpYW4oYm9zdG9uX2JnMiRtZWFuX3NjaV90MSxuYS5ybT1UKSldKSksY29sPSJibHVlIixsd2Q9MikKbGluZXMobG93ZXNzKGJvc3Rvbl9iZzIkbWVhbl9jaGFuZ2Vfc2NpW3doaWNoKGJvc3Rvbl9iZzIkbWVhbl9zY2lfdDE8PW1lZGlhbihib3N0b25fYmcyJG1lYW5fc2NpX3QxLG5hLnJtPVQpKV0gfiBsb2cxcChib3N0b25fYmcyJG5fY2FsbHNbd2hpY2goYm9zdG9uX2JnMiRtZWFuX3NjaV90MTw9bWVkaWFuKGJvc3Rvbl9iZzIkbWVhbl9zY2lfdDEsbmEucm09VCkpXSkpLGNvbD0icmVkIixsd2Q9MikKYGBgCgpgYGB7cn0KcGxvdChsb2cxcChib3N0b25fdHJhY3RzMiRuX2NhbGxzKSxib3N0b25fdHJhY3RzMiRtZWFuX2NoYW5nZV9zY2kseGxpbT1jKDAsNSkscGNoPTE2LGNvbD0iZ3JleSIsbWFpbj0iVHJhY3QtbGV2ZWwiLHlsYWI9IkNoYW5nZSBpbiBzaWRld2FsayBjb25kaXRpb25zIix4bGFiPSJOdW1iZXIgb2YgMzExIGNhbGxzIikKIyBsaW5lcyhsb3dlc3MoYm9zdG9uX3RyYWN0czIkbWVhbl9jaGFuZ2Vfc2NpIH4gbG9nMXAoYm9zdG9uX3RyYWN0czIkbl9jYWxscykpLGNvbD0icmVkIikKbGluZXMobG93ZXNzKGJvc3Rvbl90cmFjdHMyJG1lYW5fY2hhbmdlX3NjaVt3aGljaChib3N0b25fdHJhY3RzMiRtZWFuX3NjaV90MT5tZWRpYW4oYm9zdG9uX3RyYWN0czIkbWVhbl9zY2lfdDEsbmEucm09VCkpXSB+IGxvZzFwKGJvc3Rvbl90cmFjdHMyJG5fY2FsbHNbd2hpY2goYm9zdG9uX3RyYWN0czIkbWVhbl9zY2lfdDE+bWVkaWFuKGJvc3Rvbl90cmFjdHMyJG1lYW5fc2NpX3QxLG5hLnJtPVQpKV0pKSxjb2w9ImJsdWUiLGx3ZD0yKQpsaW5lcyhsb3dlc3MoYm9zdG9uX3RyYWN0czIkbWVhbl9jaGFuZ2Vfc2NpW3doaWNoKGJvc3Rvbl90cmFjdHMyJG1lYW5fc2NpX3QxPD1tZWRpYW4oYm9zdG9uX3RyYWN0czIkbWVhbl9zY2lfdDEsbmEucm09VCkpXSB+IGxvZzFwKGJvc3Rvbl90cmFjdHMyJG5fY2FsbHNbd2hpY2goYm9zdG9uX3RyYWN0czIkbWVhbl9zY2lfdDE8PW1lZGlhbihib3N0b25fdHJhY3RzMiRtZWFuX3NjaV90MSxuYS5ybT1UKSldKSksY29sPSJyZWQiLGx3ZD0yKQpgYGAKCgojIyBOaWNlciBiaXZhcmlhdGUgdmlzdWFsczoKYGBge3J9Cih0cmFjdF9iaXZhcmlhdGUgPC0gZ2dwbG90KGJvc3Rvbl90cmFjdHMyKSArIAogICAgICBnZW9tX3BvaW50KGFlcyh4PW5fY2FsbHMseT1tZWFuX2NoYW5nZV9zY2kpLGNvbD0iZ3JleSIpICsgCiAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoIk51bWJlciBvZiAzMTEgY2FsbHNcbihsb2cgc2NhbGUpIix0cmFucz0ibG9nMTAiLGJyZWFrcz1jKDEsMTAsNTAsMTAwKSkgKyAKICAgICAgIHNjYWxlX3lfY29udGludW91cygiQ2hhbmdlIGluIHNpZGV3YWxrIGNvbmRpdGlvbnMiLGxpbWl0cz1jKC00MCw0MCksYnJlYWtzPXNlcSgtNDAsNDAsMjApLGxhYmVscz1jKCJcbi00MFxuKFdvcnNlKSIsIi0yMCIsIjAiLCIyMCIsIihCZXR0ZXIpXG40MFxuIikpICsgCiAgICAgICBnZW9tX3Ntb290aChkYXRhPXN1YnNldChib3N0b25fdHJhY3RzMixtZWFuX3NjaV90MT5tZWRpYW4oYm9zdG9uX3RyYWN0czIkbWVhbl9zY2lfdDEsbmEucm09VCkpLAogICAgICAgICAgICAgICAgICAgYWVzKHg9bl9jYWxscyx5PW1lYW5fY2hhbmdlX3NjaSksY29sPSJibHVlIixsd2Q9MSxtZXRob2Q9ImxvZXNzIixzZT1GKSArIAogICAgICAgZ2VvbV9zbW9vdGgoZGF0YT1zdWJzZXQoYm9zdG9uX3RyYWN0czIsbWVhbl9zY2lfdDE8PW1lZGlhbihib3N0b25fdHJhY3RzMiRtZWFuX3NjaV90MSxuYS5ybT1UKSksCiAgICAgICAgICAgICAgICAgICBhZXMoeD1uX2NhbGxzLHk9bWVhbl9jaGFuZ2Vfc2NpKSxjb2w9InJlZCIsbHdkPTEsbWV0aG9kPSJsb2VzcyIsc2U9RikgKyAKICAgICAgIGFubm90YXRlKCJ0ZXh0Iix4PTEuNSx5PTIwLGxhYmVsPSJXb3JzZSB0cmFjdHMgaW4gMjAxMiIsY29sPSJyZWQiLHNpemU9MyxoanVzdD0wKSArCiAgICAgICBhbm5vdGF0ZSgidGV4dCIseD0xLHk9LTUsbGFiZWw9IkJldHRlciB0cmFjdHMgaW4gMjAxMiIsY29sPSJibHVlIixzaXplPTMsaGp1c3Q9MCkgKwogICAgICAgdGhlbWVfYncoKQopCmBgYApgYGB7cn0KKGJnX2JpdmFyaWF0ZSA8LSBnZ3Bsb3QoYm9zdG9uX2JnMikgKyAKICAgICAgZ2VvbV9wb2ludChhZXMoeD1uX2NhbGxzLHk9bWVhbl9jaGFuZ2Vfc2NpKSxjb2w9ImdyZXkiKSArIAogICAgICAgc2NhbGVfeF9jb250aW51b3VzKCJOdW1iZXIgb2YgMzExIGNhbGxzXG4obG9nIHNjYWxlKSIsdHJhbnM9ImxvZzEwIixsaW1pdHM9YygwLjgsMTIwKSxicmVha3M9YygxLDUsMTAsNTAsMTAwKSkgKyAKICAgICAgIHNjYWxlX3lfY29udGludW91cygiQ2hhbmdlIGluIHNpZGV3YWxrIGNvbmRpdGlvbnMiLCBsaW1pdHM9YygtNDAsNDApLCBicmVha3M9c2VxKC00MCw0MCwyMCksIGxhYmVscz1jKCJcbi00MFxuKFdvcnNlKSIsIi0yMCIsIjAiLCIyMCIsIihCZXR0ZXIpXG40MFxuIikpICsgCiAgICAgICBnZW9tX3Ntb290aChkYXRhPXN1YnNldChib3N0b25fYmcyLG1lYW5fc2NpX3QxPm1lZGlhbihib3N0b25fYmcyJG1lYW5fc2NpX3QxLG5hLnJtPVQpKSwKICAgICAgICAgICAgICAgICAgIGFlcyh4PW5fY2FsbHMseT1tZWFuX2NoYW5nZV9zY2kpLGNvbD0iYmx1ZSIsbHdkPTEsbWV0aG9kPSJsb2VzcyIsc2U9RikgKyAKICAgICAgIGdlb21fc21vb3RoKGRhdGE9c3Vic2V0KGJvc3Rvbl9iZzIsbWVhbl9zY2lfdDE8PW1lZGlhbihib3N0b25fYmcyJG1lYW5fc2NpX3QxLG5hLnJtPVQpKSwKICAgICAgICAgICAgICAgICAgIGFlcyh4PW5fY2FsbHMseT1tZWFuX2NoYW5nZV9zY2kpLGNvbD0icmVkIixsd2Q9MSxtZXRob2Q9ImxvZXNzIixzZT1GKSArIAogICAgICAgYW5ub3RhdGUoInRleHQiLHg9MS4wLHk9MTAsbGFiZWw9IldvcnNlIGJsb2NrZ3JvdXBzIGluIDIwMTIiLGNvbD0icmVkIixzaXplPTMsaGp1c3Q9MCkgKwogICAgICAgYW5ub3RhdGUoInRleHQiLHg9MSx5PS04LGxhYmVsPSJCZXR0ZXIgYmxvY2tncm91cHMgaW4gMjAxMiIsY29sPSJibHVlIixzaXplPTMsaGp1c3Q9MCkgKwogICAgICAgdGhlbWVfYncoKQopCmBgYAoKYGBge3J9CihzdHJlZXRfYml2YXJpYXRlIDwtIGdncGxvdChib3N0b25fc3RyZWV0c19zY2kpICsgCiAgICAgIGdlb21fcG9pbnQoYWVzKHg9bl9jYWxscyx5PW1lYW5fY2hhbmdlX3NjaSksY29sPSJncmV5IikgKyAKICAgICAgIHNjYWxlX3hfY29udGludW91cygiTnVtYmVyIG9mIDMxMSBjYWxsc1xuKGxvZyBzY2FsZSkiLHRyYW5zPSJsb2cxMCIsbGltaXRzPWMoMC44LDUwKSxicmVha3M9YygxLDUsMTAsMjAsNDApKSArIAogICAgICAgc2NhbGVfeV9jb250aW51b3VzKCJDaGFuZ2UgaW4gc2lkZXdhbGsgY29uZGl0aW9ucyIsIGxpbWl0cz1jKC0xMDAsMTAwKSwgYnJlYWtzPXNlcSgtMTAwLDEwMCw1MCksIGxhYmVscz1jKCJcbi0xMDBcbihXb3JzZSkiLCItNTAiLCIwIiwiNTAiLCIoQmV0dGVyKVxuMTAwXG4iKSkgKyAKICAgICAgIGdlb21fc21vb3RoKGRhdGE9c3Vic2V0KGJvc3Rvbl9zdHJlZXRzX3NjaSxtZWFuX3NjaV90MT5tZWRpYW4oYm9zdG9uX3N0cmVldHNfc2NpJG1lYW5fc2NpX3QxLG5hLnJtPVQpKSwKICAgICAgICAgICAgICAgICAgIGFlcyh4PW5fY2FsbHMseT1tZWFuX2NoYW5nZV9zY2kpLGNvbD0iYmx1ZSIsbHdkPTEsbWV0aG9kPSJsb2VzcyIsc2U9RikgKyAKICAgICAgIGdlb21fc21vb3RoKGRhdGE9c3Vic2V0KGJvc3Rvbl9zdHJlZXRzX3NjaSxtZWFuX3NjaV90MTw9bWVkaWFuKGJvc3Rvbl9zdHJlZXRzX3NjaSRtZWFuX3NjaV90MSxuYS5ybT1UKSksCiAgICAgICAgICAgICAgICAgICBhZXMoeD1uX2NhbGxzLHk9bWVhbl9jaGFuZ2Vfc2NpKSxjb2w9InJlZCIsbHdkPTEsbWV0aG9kPSJsb2VzcyIsc2U9RikgKyAKICAgICAgIGFubm90YXRlKCJ0ZXh0Iix4PTAuOCx5PTE1LGxhYmVsPSJXb3JzZSBzdHJlZXQgc2VnbWVudHMgaW4gMjAxMiIsY29sPSJyZWQiLHNpemU9MyxoanVzdD0wKSArCiAgICAgICBhbm5vdGF0ZSgidGV4dCIseD0wLjgseT0tMTUsbGFiZWw9IkJldHRlciBzdHJlZXQgc2VnbWVudHMgaW4gMjAxMiIsY29sPSJibHVlIixzaXplPTMsaGp1c3Q9MCkgKwogICAgICAgdGhlbWVfYncoKQopCmBgYAoKCmBgYHtyfQojIFNhdmluZyB2aXN1YWxzCmdnc2F2ZSh0cmFjdF9iaXZhcmlhdGUsZmlsZT0iZmlndXJlcy9jYWxsc19jaGFuZ2VTQ0lfY3QucGRmIixoZWlnaHQ9NCx3aWR0aD02KQpnZ3NhdmUoYmdfYml2YXJpYXRlLGZpbGU9ImZpZ3VyZXMvY2FsbHNfY2hhbmdlU0NJX2JnLnBkZiIsaGVpZ2h0PTQsd2lkdGg9NikKZ2dzYXZlKHN0cmVldF9iaXZhcmlhdGUsZmlsZT0iZmlndXJlcy9jYWxsc19jaGFuZ2VTQ0lfc3RyZWV0cy5wZGYiLGhlaWdodD00LHdpZHRoPTYpCmBgYAoKCiMgRGVtb2dyYXBoaWMgYW5hbHlzZXMKCk5vdyBsZXRzIGJyaW5nIGluIGRlbW9ncmFwaGljcyB0byBkbyBzb21ldGhpbmcgbW9yZSB0aGFuIGJpdmFyaWF0ZSBhbmFseXNlczoKYGBge3J9CmJnc19kYXQgPC0gdGlkeWNlbnN1czo6Z2V0X2FjcyhnZW9ncmFwaHkgPSAiYmxvY2sgZ3JvdXAiLHN0YXRlPSJNYXNzYWNodXNldHRzIix5ZWFyID0gMjAxNixvdXRwdXQgPSAid2lkZSIsCgkJCQkJCQkJCQkJCQkJCQkJdmFyaWFibGVzID0gYygiQjAxMDAzXzAwMSIsICMgdG90YWwgcG9wCgkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSJCMTkwMTNfMDAxIiwgIyBtZWRpYW4gaW5jb21lCgkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSJCMDEwMDJfMDAyIiwgIyBtZWRpYW4gYWdlCgkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSJCMTYwMTBfMDQxIiwgIyAlIGJhY2hlbG9yJ3MgZGVncmVlIG9yIGhpZ2hlcgoJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkiQjIzMDA2XzAyMyIsICMgYWxzbyBiYWNoZWxvcidzIGRlZ3JlZT8KCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJIkIwMjAwMV8wMDIiICMgd2hpdGUgcG9wIGFsb25lCgkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSkpICU+JQoJbXV0YXRlKEdFT0lEID0gYXMubnVtZXJpYyhHRU9JRCkpCiMjIGpvaW4gQUNTIGRhdGEgdG8gc2hhcGVzOgpib3N0b25fYmczIDwtIGxlZnRfam9pbihib3N0b25fYmcyLGJnc19kYXQsYnk9IkdFT0lEIikKYm9zdG9uX2JnMyA8LSBib3N0b25fYmczICU+JQoJbXV0YXRlKAoJCWhpX2luYyA9IGFzLm51bWVyaWMoQjE5MDEzXzAwMUU+PW1lZGlhbihCMTkwMTNfMDAxRSxuYS5ybT1UKSksCgkJYmFjaF9kZWdyZWVfcGVyYyA9IEIxNjAxMF8wNDFFL0IwMTAwM18wMDFFLAoJCWhpX2VkdWMgPSBhcy5udW1lcmljKGJhY2hfZGVncmVlX3BlcmM+PW1lZGlhbihiYWNoX2RlZ3JlZV9wZXJjLG5hLnJtPVQpKSwKCQl3aGl0ZV9wZXJjID0gQjAyMDAxXzAwMkUvQjAxMDAzXzAwMUUsCgkJaGlfd2hpdGUgPSBhcy5udW1lcmljKHdoaXRlX3BlcmM+PW1lZGlhbih3aGl0ZV9wZXJjLG5hLnJtPVQpKQoJCQkJICkKCmN0c19kYXQgPC0gdGlkeWNlbnN1czo6Z2V0X2FjcyhnZW9ncmFwaHkgPSAidHJhY3QiLHN0YXRlPSJNYXNzYWNodXNldHRzIix5ZWFyID0gMjAxNixvdXRwdXQgPSAid2lkZSIsCgkJCQkJCQkJCQkJCQkJCSB2YXJpYWJsZXMgPSBjKCJCMDEwMDNfMDAxIiwgIyB0b3RhbCBwb3AKCQkJCQkJCQkJCQkJCQkJIAkJCQkJCQkiQjE5MDEzXzAwMSIsICMgbWVkaWFuIGluY29tZQoJCQkJCQkJCQkJCQkJCQkgCQkJCQkJCSJCMDEwMDJfMDAyIiwgIyBtZWRpYW4gYWdlCgkJCQkJCQkJCQkJCQkJCSAJCQkJCQkJIkIxNjAxMF8wNDEiLCAjICUgYmFjaGVsb3IncyBkZWdyZWUgb3IgaGlnaGVyCgkJCQkJCQkJCQkJCQkJCSAJCQkJCQkJIkIyMzAwNl8wMjMiLCAjIGFsc28gYmFjaGVsb3IncyBkZWdyZWU/CgkJCQkJCQkJCQkJCQkJCSAJCQkJCQkJIkIwMjAwMV8wMDIiICMgd2hpdGUgcG9wIGFsb25lCgkJCQkJCQkJCQkJCQkJCSApKSAlPiUKCW11dGF0ZShHRU9JRCA9IGFzLm51bWVyaWMoR0VPSUQpKQojIyBqb2luIEFDUyBkYXRhIHRvIHNoYXBlczoKYm9zdG9uX3RyYWN0czMgPC0gbGVmdF9qb2luKGJvc3Rvbl90cmFjdHMyLGN0c19kYXQsYnk9IkdFT0lEIikKIyBjcmVhdGUgYmlubmVkIHZhcmlhYmxlczoKYm9zdG9uX3RyYWN0czMgPC0gYm9zdG9uX3RyYWN0czMgJT4lCgltdXRhdGUoCgkJaGlfaW5jID0gYXMubnVtZXJpYyhCMTkwMTNfMDAxRT49bWVkaWFuKEIxOTAxM18wMDFFLG5hLnJtPVQpKSwKCQliYWNoX2RlZ3JlZV9wZXJjID0gQjE2MDEwXzA0MUUvQjAxMDAzXzAwMUUsCgkJaGlfZWR1YyA9IGFzLm51bWVyaWMoYmFjaF9kZWdyZWVfcGVyYz49bWVkaWFuKGJhY2hfZGVncmVlX3BlcmMsbmEucm09VCkpLAoJCXdoaXRlX3BlcmMgPSBCMDIwMDFfMDAyRS9CMDEwMDNfMDAxRSwKCQloaV93aGl0ZSA9IGFzLm51bWVyaWMod2hpdGVfcGVyYz49bWVkaWFuKHdoaXRlX3BlcmMsbmEucm09VCkpCgkJCQkgKQoKIyMjIEJhc2ljIGFuYWx5c2VzIG9mIGltcHJvdmVtZW50IGluIGNvbmRpdGlvbnMKIyMgVHJhY3QtbGV2ZWw6CiMgaW5jb21lOgpzdW1tYXJ5KGxtKGJvc3Rvbl90cmFjdHMzJG1lYW5fY2hhbmdlX3NjaSB+IChib3N0b25fdHJhY3RzMyRuX2NhbGxzPjApKSkKc3VtbWFyeShsbShib3N0b25fdHJhY3RzMyRtZWFuX2NoYW5nZV9zY2kgfiBsb2cxcChib3N0b25fdHJhY3RzMyRuX2NhbGxzKSkpCnN1bW1hcnkobG0oKGJvc3Rvbl90cmFjdHMzJGNoYW5nZV9zY2k9PSJCZXR0ZXIiKSB+IGxvZzFwKGJvc3Rvbl90cmFjdHMzJG5fY2FsbHMpKSkgIyBuZWdhdGl2ZSwgaW5zaWcKc3VtbWFyeShsbShtZWFuX2NoYW5nZV9zY2kgfiBoaV9pbmMsZGF0YT1ib3N0b25fdHJhY3RzMykpICMgaW5zaWcgcG9zaXRpdmUgZWZmZWN0CnN1bW1hcnkobG0oY2hhbmdlX3NjaV9iaW5uZWQ9PSJCZXR0ZXIiIH4gaGlfaW5jLGRhdGE9Ym9zdG9uX3RyYWN0czMpKSAjIGluc2lnIG5lZyBlZmZlY3QKc3VtbWFyeShsbShtZWFuX2NoYW5nZV9zY2kgfiBCMTkwMTNfMDAxRSxkYXRhPWJvc3Rvbl90cmFjdHMzKSkgIyBpbnNpZyBuZWcgZWZmZWN0CnN1bW1hcnkobG0oY2hhbmdlX3NjaV9iaW5uZWQ9PSJCZXR0ZXIiIH4gQjE5MDEzXzAwMUUsZGF0YT1ib3N0b25fdHJhY3RzMykpICMgaW5zaWcgbmVnIGVmZmVjdAoKc3VtbWFyeShsbSgoY2hhbmdlX3NjaV9iaW5uZWQ9PSJCZXR0ZXIiKSB+IG5fY2FsbHMqQjE5MDEzXzAwMUUsIGRhdGEgPSBib3N0b25fdHJhY3RzMykpICMgZGlmZmVyZW50aWFsIGltcGFjdCBvZiBjYWxsczogbm90aGluZyBzaWcsIGhpZ2hlciBpbmNvbWUgYXJlYXMgc2xpZ2h0bHkgc21hbGxlciBlZmZlY3Qgb2Ygbl9jYWxscwpzdW1tYXJ5KGxtKG1lYW5fY2hhbmdlX3NjaSB+IG5fY2FsbHMqQjE5MDEzXzAwMUUsIGRhdGEgPSBib3N0b25fdHJhY3RzMykpICMgbm90aGluZyBzaWcKc3VtbWFyeShsbShtZWFuX2NoYW5nZV9zY2kgfiBsb2cxcChuX2NhbGxzKSpCMTkwMTNfMDAxRSwgZGF0YSA9IGJvc3Rvbl90cmFjdHMzKSkgIyBub3RoaW5nIHNpZwpzdW1tYXJ5KGxtKChjaGFuZ2Vfc2NpX2Jpbm5lZD09IkJldHRlciIpIH4gbG9nMXAobl9jYWxscykqQjE5MDEzXzAwMUUsIGRhdGEgPSBib3N0b25fdHJhY3RzMykpICMgZGlmZmVyZW50aWFsIGltcGFjdCBvZiBjYWxsczogbm90aGluZyBzaWcsIGhpZ2hlciBpbmNvbWUgYXJlYXMgc2xpZ2h0bHkgc21hbGxlciBlZmZlY3Qgb2Ygbl9jYWxscwpzdW1tYXJ5KGxtKG1lYW5fY2hhbmdlX3NjaSB+IGxvZzFwKG5fY2FsbHMpKkIxOTAxM18wMDFFLCBkYXRhID0gYm9zdG9uX3RyYWN0czMpKSAjIGRpZmZlcmVudGlhbCBpbXBhY3Qgb2YgY2FsbHM6IG5vdGhpbmcgc2lnCgojIHJhY2U6CnN1bW1hcnkobG0obWVhbl9jaGFuZ2Vfc2NpIH4gd2hpdGVfcGVyYywgZGF0YSA9IGJvc3Rvbl90cmFjdHMzKSkgIyB3aGl0ZXIgdHJhY3RzIGhhdmUgbXVjaCBiZXR0ZXIgaW1wcm92ZW1lbnQKc3VtbWFyeShsbShtZWFuX2NoYW5nZV9zY2kgfiBoaV93aGl0ZSwgZGF0YSA9IGJvc3Rvbl90cmFjdHMzKSkgIyB3aGl0ZXIgdHJhY3RzIGhhdmUgbXVjaCBiZXR0ZXIgaW1wcm92ZW1lbnQKc3VtbWFyeShsbShtZWFuX2NoYW5nZV9zY2kgfiBsb2cxcChuX2NhbGxzKSp3aGl0ZV9wZXJjLCBkYXRhID0gYm9zdG9uX3RyYWN0czMpKSAjIHdoaXRlciB0cmFjdHMgaGF2ZSBtb3JlIGltcHJvdmVtZW50LCBtYXJnaW5hbCBuZWcgaW50eApzdW1tYXJ5KGxtKG1lYW5fY2hhbmdlX3NjaSB+IGxvZzFwKG5fY2FsbHMpKmhpX3doaXRlLCBkYXRhID0gYm9zdG9uX3RyYWN0czMpKSAjIHdoaXRlciB0cmFjdHMgaGF2ZSBtb3JlIGltcHJvdmVtZW50LCBzaWcgbmVnIGludHgKc3VtbWFyeShsbShjaGFuZ2Vfc2NpX2Jpbm5lZD09IkJldHRlciIgfiBsb2cxcChuX2NhbGxzKSp3aGl0ZV9wZXJjLCBkYXRhID0gYm9zdG9uX3RyYWN0czMpKSAjIHdoaXRlciB0cmFjdHMgaGF2ZSBtb3JlIGltcHJvdmVtZW50LCBtYXJnaW5hbCBuZWcgaW50eApzdW1tYXJ5KGxtKGNoYW5nZV9zY2lfYmlubmVkPT0iQmV0dGVyIiB+IGxvZzFwKG5fY2FsbHMpKmhpX3doaXRlLCBkYXRhID0gYm9zdG9uX3RyYWN0czMpKSAjIHdoaXRlciB0cmFjdHMgaGF2ZSBtb3JlIGltcHJvdmVtZW50LCBzaWcgbmVnIGludHgKCiMjIEJHLWxldmVsCiMgaW5jb21lOgpzdW1tYXJ5KGxtKG1lYW5fY2hhbmdlX3NjaSB+IChuX2NhbGxzPjApLGRhdGE9Ym9zdG9uX2JnMykpICMgaW5zaWcgcG9zaXRpdmUKc3VtbWFyeShsbSgoY2hhbmdlX3NjaV9iaW5uZWQ9PSJCZXR0ZXIiKSB+IGxvZzFwKG5fY2FsbHMpLGRhdGE9Ym9zdG9uX2JnMykpICMgaW5zaWcgbmVnYXRpdmUKc3VtbWFyeShsbShtZWFuX2NoYW5nZV9zY2kgfiBoaV9pbmMsZGF0YT1ib3N0b25fYmczKSkgIyBpbnNpZyBwb3NpdGl2ZSBlZmZlY3QKc3VtbWFyeShsbShjaGFuZ2Vfc2NpX2Jpbm5lZD09IkJldHRlciIgfiBoaV9pbmMsZGF0YT1ib3N0b25fYmczKSkgIyBpbnNpZyBwb3MgZWZmZWN0CnN1bW1hcnkobG0obWVhbl9jaGFuZ2Vfc2NpIH4gQjE5MDEzXzAwMUUsZGF0YT1ib3N0b25fYmczKSkgIyBpbnNpZyBwb3MgZWZmZWN0CnN1bW1hcnkobG0oY2hhbmdlX3NjaV9iaW5uZWQ9PSJCZXR0ZXIiIH4gQjE5MDEzXzAwMUUsZGF0YT1ib3N0b25fYmczKSkgIyBpbnNpZyBwb3MgZWZmZWN0CgpzdW1tYXJ5KGxtKChjaGFuZ2Vfc2NpX2Jpbm5lZD09IkJldHRlciIpIH4gbl9jYWxscypCMTkwMTNfMDAxRSwgZGF0YSA9IGJvc3Rvbl9iZzMpKSAjIGRpZmZlcmVudGlhbCBpbXBhY3Qgb2YgY2FsbHM6IG5vdGhpbmcgc2lnLCBoaWdoZXIgaW5jb21lIGFyZWFzIHNsaWdodGx5IHNtYWxsZXIgZWZmZWN0IG9mIG5fY2FsbHMKc3VtbWFyeShsbShtZWFuX2NoYW5nZV9zY2kgfiBuX2NhbGxzKkIxOTAxM18wMDFFLCBkYXRhID0gYm9zdG9uX2JnMykpICMgZGlmZmVyZW50aWFsIGltcGFjdCBvZiBjYWxsczogbm90aGluZyBzaWcKc3VtbWFyeShsbSgoY2hhbmdlX3NjaV9iaW5uZWQ9PSJCZXR0ZXIiKSB+IGxvZzFwKG5fY2FsbHMpKkIxOTAxM18wMDFFLCBkYXRhID0gYm9zdG9uX2JnMykpICMgZGlmZmVyZW50aWFsIGltcGFjdCBvZiBjYWxsczogbm90aGluZyBzaWcsIGhpZ2hlciBpbmNvbWUgYXJlYXMgc2xpZ2h0bHkgc21hbGxlciBlZmZlY3Qgb2Ygbl9jYWxscwpzdW1tYXJ5KGxtKG1lYW5fY2hhbmdlX3NjaSB+IGxvZzFwKG5fY2FsbHMpKkIxOTAxM18wMDFFLCBkYXRhID0gYm9zdG9uX2JnMykpICMgcG9zIHNpZyBlZmZlY3Qgb2YgY2FsbHMsIHBvcyBzaWcgZWZmZWN0IG9mIGluY29tZSwgbmVnIHNpZyBpbnR4OiBjYWxscyBoYXZlIGxlc3MgaW1wYWN0IGluIHdlYWx0aGllciBCR3MKc3VtbWFyeShsbShtZWFuX2NoYW5nZV9zY2kgfiBsb2cxcChuX2NhbGxzKSpoaV9pbmMsIGRhdGEgPSBib3N0b25fYmczKSkgIyBwb3Mgc2lnIGVmZmVjdCBvZiBjYWxscywgcG9zIHNpZyBlZmZlY3Qgb2YgaW5jb21lLCBuZWcgc2lnIGludHgKc3VtbWFyeShsbShtZWFuX2NoYW5nZV9zY2kgfiBsb2cxcChuX2NhbGxzKSwgZGF0YSA9IHN1YnNldChib3N0b25fYmczLCBoaV9pbmM9PTEpKSkgIyBuZWcgaW5zaWcgZWZmZWN0IGFtb25nIGhpLWluY29tZQpzdW1tYXJ5KGxtKG1lYW5fY2hhbmdlX3NjaSB+IGxvZzFwKG5fY2FsbHMpLCBkYXRhID0gc3Vic2V0KGJvc3Rvbl9iZzMsIGhpX2luYz09MCkpKSAjIHBvcyBzaWcgZWZmZWN0IGFtb25nIGxvdy1pbmNvbWUKc3VtbWFyeShsbShjaGFuZ2Vfc2NpX2Jpbm5lZD09IkJldHRlciIgfiBsb2cxcChuX2NhbGxzKSpoaV9pbmMsIGRhdGEgPSBib3N0b25fYmczKSkgIyBhbGwgaW5zaWcKc3VtbWFyeShsbShjaGFuZ2Vfc2NpX2Jpbm5lZD09IkJldHRlciIgfiAobl9jYWxscykqaGlfaW5jLCBkYXRhID0gYm9zdG9uX2JnMykpICMgbWFyZ2luYWwgbmVnIGludHgKCgojIHJhY2U6CnN1bW1hcnkobG0obWVhbl9jaGFuZ2Vfc2NpIH4gd2hpdGVfcGVyYywgZGF0YSA9IGJvc3Rvbl9iZzMpKSAjIHdoaXRlciBCR3MgaGF2ZSBtdWNoIGJldHRlciBpbXByb3ZlbWVudApzdW1tYXJ5KGxtKG1lYW5fY2hhbmdlX3NjaSB+IGhpX3doaXRlLCBkYXRhID0gYm9zdG9uX2JnMykpICMgd2hpdGVyIEJHcyBoYXZlIG11Y2ggYmV0dGVyIGltcHJvdmVtZW50CnN1bW1hcnkobG0obWVhbl9jaGFuZ2Vfc2NpIH4gbG9nMXAobl9jYWxscykqd2hpdGVfcGVyYywgZGF0YSA9IGJvc3Rvbl9iZzMpKSAjIHBvcyBzaWcgZWZmZWN0IG9mIGNhbGxzLCBwb3Mgc2lnIGVmZmVjdCBvZiB3aGl0ZSwgbmVnIHNpZyBpbnR4CnN1bW1hcnkobG0obWVhbl9jaGFuZ2Vfc2NpIH4gbG9nMXAobl9jYWxscykqaGlfd2hpdGUsIGRhdGEgPSBib3N0b25fYmczKSkgIyBwb3Mgc2lnIGVmZmVjdCBvZiBjYWxscywgcG9zIHNpZyBlZmZlY3Qgb2Ygd2hpdGUsIG5lZyBzaWcgaW50eApzdW1tYXJ5KGxtKGNoYW5nZV9zY2lfYmlubmVkPT0iQmV0dGVyIiB+IGxvZzFwKG5fY2FsbHMpKndoaXRlX3BlcmMsIGRhdGEgPSBib3N0b25fYmczKSkgIyBwb3Mgc2lnIGVmZmVjdCBvZiBjYWxscywgcG9zIHNpZyBlZmZlY3Qgb2Ygd2hpdGUsIG5lZyBzaWcgaW50eApzdW1tYXJ5KGxtKGNoYW5nZV9zY2lfYmlubmVkPT0iQmV0dGVyIiB+IGxvZzFwKG5fY2FsbHMpKmhpX3doaXRlLCBkYXRhID0gYm9zdG9uX2JnMykpICMgcG9zIGluc2lnIGVmZmVjdCBvZiBjYWxscywgcG9zIHNpZyBlZmZlY3Qgb2Ygd2hpdGUsIG5lZyBzaWcgaW50eApgYGAKVGhlIG1haW4gbGVzc29ucyBjb21pbmcgb3V0IG9mIHRoZXNlIGFuYWx5c2VzIGFyZSB0aGF0OgooMSkgV2hpdGVyIGFuZCBoaWdoZXIgaW5jb21lIHRyYWN0cyBhbmQgQkdzIHdlcmUgbW9yZSBsaWtlbHkgdG8gaGF2ZSBpbXByb3ZlbWVudCBpbiBzaWRld2FsayBjb25kaXRpb25zIGJldHdlZW4gdGhlIHR3byBzaWRld2FsayBjb25kaXRpb25zIGF1ZGl0czsgYW5kCigyKSBJbiB0cmFjdHMgYW5kIEJHcyB3aXRoIG1vcmUgd2hpdGUgcmVzaWRlbnRzIGFuZCB3aXRoIGhpZ2hlciBsZXZlbHMgb2YgZWR1Y2F0aW9uLCB0aGUgbnVtYmVyIG9mIDMxMSBjYWxscyBkb2Vzbid0IHNlZW0gdG8gY29ycmVsYXRlIHdpdGggaW1wcm92ZW1lbnRzIGluIHNpZGV3YWxrIGNvbmRpdGlvbnMsIGJ1dCBpbiB0cmFjdHMgYW5kIEJHcyB3aXRoICpmZXdlciogd2hpdGUgcmVzaWRlbnRzIGFuZCAqbG93ZXIqIGxldmVscyBvZiBlZHVjYXRpb24sIHRoZSBudW1iZXIgb2YgMzExIGNhbGxzIGlzIHBvc2l0aXZlbHkgY29ycmVsYXRlZCB3aXRoIGltcHJvdmVtZW50cyBpbiBzaWRld2FsayBjb25kaXRpb25zLgoKCiMjIFZpc3VhbGl6aW5nIHRoZXNlIGR5bmFtaWNzOgpgYGB7cn0KKHRyYWN0X2JpdmFyaWF0ZV9yYWNlIDwtIGdncGxvdChib3N0b25fdHJhY3RzMykgKyAKICAgICAgZ2VvbV9wb2ludChhZXMoeD1uX2NhbGxzLHk9bWVhbl9jaGFuZ2Vfc2NpKSxjb2w9ImdyZXkiKSArIAogICAgICAgc2NhbGVfeF9jb250aW51b3VzKCJOdW1iZXIgb2YgMzExIGNhbGxzXG4obG9nIHNjYWxlKSIsdHJhbnM9ImxvZzEwIixicmVha3M9YygxLDEwLDUwLDEwMCkpICsgCiAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoIkNoYW5nZSBpbiBzaWRld2FsayBjb25kaXRpb25zIiwgbGltaXRzPWMoLTQwLDQwKSwgYnJlYWtzPXNlcSgtNDAsNDAsMjApLCBsYWJlbHM9YygiXG4tNDBcbihXb3JzZSkiLCItMjAiLCIwIiwiMjAiLCIoQmV0dGVyKVxuNDBcbiIpKSArIAogICAgICAgZ2VvbV9zbW9vdGgoZGF0YT1zdWJzZXQoYm9zdG9uX3RyYWN0czMsIGhpX3doaXRlPT0xKSwKICAgICAgICAgICAgICAgICAgIGFlcyh4PW5fY2FsbHMseT1tZWFuX2NoYW5nZV9zY2kpLGNvbD0icmVkIixsd2Q9MSxtZXRob2Q9ImxvZXNzIixzZT1GKSArIAogICAgICAgZ2VvbV9zbW9vdGgoZGF0YT1zdWJzZXQoYm9zdG9uX3RyYWN0czMsaGlfd2hpdGU9PTApLAogICAgICAgICAgICAgICAgICAgYWVzKHg9bl9jYWxscyx5PW1lYW5fY2hhbmdlX3NjaSksY29sPSJibHVlIixsd2Q9MSxtZXRob2Q9ImxvZXNzIixzZT1GKSArIAogICAgICAgYW5ub3RhdGUoInRleHQiLHg9MS41LHk9MjUsbGFiZWw9IkFib3ZlIG1lZGlhbiAlIHdoaXRlIixjb2w9InJlZCIsc2l6ZT0zLGhqdXN0PTApICsKICAgICAgIGFubm90YXRlKCJ0ZXh0Iix4PTEseT0tNSxsYWJlbD0iQmVsb3cgbWVkaWFuICUgd2hpdGUiLGNvbD0iYmx1ZSIsc2l6ZT0zLGhqdXN0PTApICsKICAgICAgIHRoZW1lX2J3KCkKKQpgYGAKCgpgYGB7cn0KKGJnX2JpdmFyaWF0ZV9yYWNlIDwtIGdncGxvdChib3N0b25fYmczKSArIAogICAgICBnZW9tX3BvaW50KGFlcyh4PW5fY2FsbHMseT1tZWFuX2NoYW5nZV9zY2kpLGNvbD0iZ3JleSIpICsgCiAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoIk51bWJlciBvZiAzMTEgY2FsbHNcbihsb2cgc2NhbGUpIix0cmFucz0ibG9nMTAiLGJyZWFrcz1jKDEsMTAsNTAsMTAwKSkgKyAKICAgICAgIHNjYWxlX3lfY29udGludW91cygiQ2hhbmdlIGluIHNpZGV3YWxrIGNvbmRpdGlvbnMiLCBsaW1pdHM9YygtNDAsNDApLCBicmVha3M9c2VxKC00MCw0MCwyMCksIGxhYmVscz1jKCJcbi00MFxuKFdvcnNlKSIsIi0yMCIsIjAiLCIyMCIsIihCZXR0ZXIpXG40MFxuIikpICsgCiAgICAgICBnZW9tX3Ntb290aChkYXRhPXN1YnNldChib3N0b25fYmczLCBoaV93aGl0ZT09MSksCiAgICAgICAgICAgICAgICAgICBhZXMoeD1uX2NhbGxzLHk9bWVhbl9jaGFuZ2Vfc2NpKSxjb2w9InJlZCIsbHdkPTEsbWV0aG9kPSJsb2VzcyIsc2U9RikgKyAKICAgICAgIGdlb21fc21vb3RoKGRhdGE9c3Vic2V0KGJvc3Rvbl9iZzMsaGlfd2hpdGU9PTApLAogICAgICAgICAgICAgICAgICAgYWVzKHg9bl9jYWxscyx5PW1lYW5fY2hhbmdlX3NjaSksY29sPSJibHVlIixsd2Q9MSxtZXRob2Q9ImxvZXNzIixzZT1GKSArIAogICAgICAgYW5ub3RhdGUoInRleHQiLHg9MSx5PTEyLGxhYmVsPSJBYm92ZSBtZWRpYW4gJSB3aGl0ZSIsY29sPSJyZWQiLHNpemU9MyxoanVzdD0wKSArCiAgICAgICBhbm5vdGF0ZSgidGV4dCIseD0xLHk9LTksbGFiZWw9IkJlbG93IG1lZGlhbiAlIHdoaXRlIixjb2w9ImJsdWUiLHNpemU9MyxoanVzdD0wKSArCiAgICAgICB0aGVtZV9idygpCikKYGBgCgoKCmBgYHtyfQpnZ3NhdmUodHJhY3RfYml2YXJpYXRlX3JhY2UsZmlsZT0iZmlndXJlcy9jYWxsc19jaGFuZ2VTQ0lfY3RfcmFjZS5wZGYiLGhlaWdodD00LHdpZHRoPTYpCmdnc2F2ZShiZ19iaXZhcmlhdGVfcmFjZSxmaWxlPSJmaWd1cmVzL2NhbGxzX2NoYW5nZVNDSV9iZ19yYWNlLnBkZiIsaGVpZ2h0PTQsd2lkdGg9NikKYGBgCgoKCmBgYHtyfQoodHJhY3RfYml2YXJpYXRlX2luYyA8LSBnZ3Bsb3QoYm9zdG9uX3RyYWN0czMpICsgCiAgICAgIGdlb21fcG9pbnQoYWVzKHg9bl9jYWxscyx5PW1lYW5fY2hhbmdlX3NjaSksY29sPSJncmV5IikgKyAKICAgICAgIHNjYWxlX3hfY29udGludW91cygiTnVtYmVyIG9mIDMxMSBjYWxsc1xuKGxvZyBzY2FsZSkiLHRyYW5zPSJsb2cxMCIsYnJlYWtzPWMoMSwxMCw1MCwxMDApKSArIAogICAgICAgc2NhbGVfeV9jb250aW51b3VzKCJDaGFuZ2UgaW4gc2lkZXdhbGsgY29uZGl0aW9ucyIsIGxpbWl0cz1jKC00MCw0MCksIGJyZWFrcz1zZXEoLTQwLDQwLDIwKSwgbGFiZWxzPWMoIlxuLTQwXG4oV29yc2UpIiwiLTIwIiwiMCIsIjIwIiwiKEJldHRlcilcbjQwXG4iKSkgKyAKICAgICAgIGdlb21fc21vb3RoKGRhdGE9c3Vic2V0KGJvc3Rvbl90cmFjdHMzLCBoaV9pbmM9PTEpLAogICAgICAgICAgICAgICAgICAgYWVzKHg9bl9jYWxscyx5PW1lYW5fY2hhbmdlX3NjaSksY29sPSJyZWQiLGx3ZD0xLG1ldGhvZD0ibG9lc3MiLHNlPUYpICsgCiAgICAgICBnZW9tX3Ntb290aChkYXRhPXN1YnNldChib3N0b25fdHJhY3RzMyxoaV9pbmM9PTApLAogICAgICAgICAgICAgICAgICAgYWVzKHg9bl9jYWxscyx5PW1lYW5fY2hhbmdlX3NjaSksY29sPSJibHVlIixsd2Q9MSxtZXRob2Q9ImxvZXNzIixzZT1GKSArIAogICAgICAgYW5ub3RhdGUoInRleHQiLHg9MTAseT0xNSxsYWJlbD0iQWJvdmUgbWVkaWFuIGluY29tZSIsY29sPSJyZWQiLHNpemU9MyxoanVzdD0wKSArCiAgICAgICBhbm5vdGF0ZSgidGV4dCIseD0xLHk9LTUsbGFiZWw9IkJlbG93IG1lZGlhbiBpbmNvbWUiLGNvbD0iYmx1ZSIsc2l6ZT0zLGhqdXN0PTApICsKICAgICAgIHRoZW1lX2J3KCkKKQpgYGAKCgpgYGB7cn0KKGJnX2JpdmFyaWF0ZV9pbmMgPC0gZ2dwbG90KGJvc3Rvbl9iZzMpICsgCiAgICAgIGdlb21fcG9pbnQoYWVzKHg9bl9jYWxscyx5PW1lYW5fY2hhbmdlX3NjaSksY29sPSJncmV5IikgKyAKICAgICAgIHNjYWxlX3hfY29udGludW91cygiTnVtYmVyIG9mIDMxMSBjYWxsc1xuKGxvZyBzY2FsZSkiLHRyYW5zPSJsb2cxMCIsYnJlYWtzPWMoMSwxMCw1MCwxMDApKSArIAogICAgICAgc2NhbGVfeV9jb250aW51b3VzKCJDaGFuZ2UgaW4gc2lkZXdhbGsgY29uZGl0aW9ucyIsIGxpbWl0cz1jKC00MCw0MCksIGJyZWFrcz1zZXEoLTQwLDQwLDIwKSwgbGFiZWxzPWMoIlxuLTQwXG4oV29yc2UpIiwiLTIwIiwiMCIsIjIwIiwiKEJldHRlcilcbjQwXG4iKSkgKyAKICAgICAgIGdlb21fc21vb3RoKGRhdGE9c3Vic2V0KGJvc3Rvbl9iZzMsIGhpX2luYz09MSksCiAgICAgICAgICAgICAgICAgICBhZXMoeD1uX2NhbGxzLHk9bWVhbl9jaGFuZ2Vfc2NpKSxjb2w9InJlZCIsbHdkPTEsbWV0aG9kPSJsb2VzcyIsc2U9RikgKyAKICAgICAgIGdlb21fc21vb3RoKGRhdGE9c3Vic2V0KGJvc3Rvbl9iZzMsaGlfaW5jPT0wKSwKICAgICAgICAgICAgICAgICAgIGFlcyh4PW5fY2FsbHMseT1tZWFuX2NoYW5nZV9zY2kpLGNvbD0iYmx1ZSIsbHdkPTEsbWV0aG9kPSJsb2VzcyIsc2U9RikgKyAKICAgICAgIGFubm90YXRlKCJ0ZXh0Iix4PTEseT0xMCxsYWJlbD0iQWJvdmUgbWVkaWFuIGluY29tZSIsY29sPSJyZWQiLHNpemU9MyxoanVzdD0wKSArCiAgICAgICBhbm5vdGF0ZSgidGV4dCIseD0xLHk9LTksbGFiZWw9IkJlbG93IG1lZGlhbiBpbmNvbWUiLGNvbD0iYmx1ZSIsc2l6ZT0zLGhqdXN0PTApICsKICAgICAgIHRoZW1lX2J3KCkKKQpgYGAKYGBge3J9CihiZ19iaXZhcmlhdGVfaW5jX2xtIDwtIGdncGxvdChib3N0b25fYmczKSArIAogICAgICBnZW9tX3BvaW50KGFlcyh4PW5fY2FsbHMseT1tZWFuX2NoYW5nZV9zY2kpLGNvbD0iZ3JleSIpICsgCiAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoIk51bWJlciBvZiAzMTEgY2FsbHNcbihsb2cgc2NhbGUpIix0cmFucz0ibG9nMTAiLGJyZWFrcz1jKDEsMTAsNTAsMTAwKSkgKyAKICAgICAgIHNjYWxlX3lfY29udGludW91cygiQ2hhbmdlIGluIHNpZGV3YWxrIGNvbmRpdGlvbnMiLCBsaW1pdHM9YygtNDAsNDApLCBicmVha3M9c2VxKC00MCw0MCwyMCksIGxhYmVscz1jKCJcbi00MFxuKFdvcnNlKSIsIi0yMCIsIjAiLCIyMCIsIihCZXR0ZXIpXG40MFxuIikpICsgCiAgICAgICBnZW9tX3Ntb290aChkYXRhPXN1YnNldChib3N0b25fYmczLCBoaV9pbmM9PTEpLAogICAgICAgICAgICAgICAgICAgYWVzKHg9bl9jYWxscyx5PW1lYW5fY2hhbmdlX3NjaSksY29sPSJyZWQiLGx3ZD0xLG1ldGhvZD0ibG0iLHNlPUYpICsgCiAgICAgICBnZW9tX3Ntb290aChkYXRhPXN1YnNldChib3N0b25fYmczLGhpX2luYz09MCksCiAgICAgICAgICAgICAgICAgICBhZXMoeD1uX2NhbGxzLHk9bWVhbl9jaGFuZ2Vfc2NpKSxjb2w9ImJsdWUiLGx3ZD0xLG1ldGhvZD0ibG0iLHNlPUYpICsgCiAgICAgICBhbm5vdGF0ZSgidGV4dCIseD0xLHk9MTAsbGFiZWw9IkFib3ZlIG1lZGlhbiBpbmNvbWUiLGNvbD0icmVkIixzaXplPTMsaGp1c3Q9MCkgKwogICAgICAgYW5ub3RhdGUoInRleHQiLHg9MSx5PS05LGxhYmVsPSJCZWxvdyBtZWRpYW4gaW5jb21lIixjb2w9ImJsdWUiLHNpemU9MyxoanVzdD0wKSArCiAgICAgICB0aGVtZV9idygpCikKYGBgCgpgYGB7cn0KIyBzYXZpbmcgcGxvdHM6Cmdnc2F2ZSh0cmFjdF9iaXZhcmlhdGVfaW5jLGZpbGU9ImZpZ3VyZXMvY2FsbHNfY2hhbmdlU0NJX2N0X2luYy5wZGYiLGhlaWdodD00LHdpZHRoPTYpCmdnc2F2ZShiZ19iaXZhcmlhdGVfaW5jLGZpbGU9ImZpZ3VyZXMvY2FsbHNfY2hhbmdlU0NJX2JnX2luYy5wZGYiLGhlaWdodD00LHdpZHRoPTYpCmdnc2F2ZShiZ19iaXZhcmlhdGVfaW5jX2xtLGZpbGU9ImZpZ3VyZXMvY2FsbHNfY2hhbmdlU0NJX2JnX2luY19sbS5wZGYiLGhlaWdodD00LHdpZHRoPTYpCmBgYAoKCmBgYHtyfQojIHNhdmluZyBpbWFnZSBvZiB3b3JrCnNhdmUuaW1hZ2UoInN0cmVldGNhc3Rlcl93c18xODEwMzAuUkRhdGEiKQpgYGA=