diff --git a/rainlink.nb.html b/rainlink.nb.html deleted file mode 100644 index 361aa8c..0000000 --- a/rainlink.nb.html +++ /dev/null @@ -1,2160 +0,0 @@ - - - - - - - - - - - - - -RAINLINK Notebook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - -

The RAINLINK package. Retrieval algorithm for rainfall mapping from microwave links in a cellular communication network.

-

Version 1.14 Copyright (C) 2019 Aart Overeem

-

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

-

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

-

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

-

Note that it is not necessarily a problem if a function argument is not supplied to the function. If the function argument is not used, then there is no problem. Only be aware that you should use e.g. MaxFrequency=MaxFrequency. I.e. if you only supply MaxFrequency and the function argument before MaxFrequency is missing, than the function will not execute properly.

-
-

0. Load R libraries, parameter values, and other settings.

-

This also loads the RAINLINK package.

- - -

If the time zone of the employed microwave link dataset is not the same as the (local) time zone used by R on your computer, set the time zone of the microwave link dataset: (this is important for functions RefLevelMinMaxRSL, WetDryNearbyLinkApMinMaxRSL and Interpolation):

- - - -
Sys.setenv(TZ='UTC')
- - - -

Otherwise RAINLINK can derive a wrong time interval length due to going to or from daylight saving time (DST). Timing of DST may be different between time zones, or one time zone may not have a change to/from DST.

-
-
-

1. PreprocessingMinMaxRSL

- - - -
# Load data:
-load("data/Linkdata_vodafone2016.RData")
-# summary(Linkdata)
-# Add column with polarization if this column is not supplied in the link data:
-if ("Polarization" %in% names(Linkdata)==FALSE)
-{
-  Linkdata$Polarization <- rep(NA,nrow(Linkdata))
-}
- - - -

When no information on polarization is provided, the above code creates a column of NA for Polarization. In the function “RainRetrievalMinMaxRSL.R” links with NA values for polarization are processed with a & b values determined for vertically polarized signals. If information on polarization of links is available, use H for horizontally polarized & V for vertically polarized in “Linkdata Polarization”. H, V & NA may occur in the same Linkdata file.

- - - -
# Run R function:
-StartTime <- proc.time()
-DataPreprocessed <- PreprocessingMinMaxRSL(Data=Linkdata,
-                                           MaxFrequency=MaxFrequency,
-                                           MinFrequency=MinFrequency,
-                                           verbose=TRUE)
-cat(sprintf("Finished. (%.1f seconds)\n",round((proc.time()-StartTime)[3],digits=1))) # ~ 360 s
- - -
Finished. (319.6 seconds)
- - -
summary(DataPreprocessed)
- - -
   Frequency             DateTime            Pmin              Pmax           PathLength     
- Min.   : 6.00   201606290945:    641   Min.   :-108.00   Min.   :-100.00   Min.   : 0.1618  
- 1st Qu.:17.75   201606291015:    641   1st Qu.: -49.00   1st Qu.: -48.00   1st Qu.: 1.9777  
- Median :19.53   201606291030:    641   Median : -44.00   Median : -44.00   Median : 4.0783  
- Mean   :23.38   201606291100:    641   Mean   : -44.95   Mean   : -43.98   Mean   : 5.4344  
- 3rd Qu.:23.05   201606291115:    641   3rd Qu.: -40.00   3rd Qu.: -39.00   3rd Qu.: 7.1872  
- Max.   :42.59   201606291130:    641   Max.   : -21.00   Max.   : -16.00   Max.   :29.7374  
-                 (Other)     :5481725                                                        
-     XStart           YStart           XEnd             YEnd                   Label        
- Min.   : 9.617   Min.   :44.09   Min.   : 9.617   Min.   :44.09   2-Q6885/2-Q6886:  24684  
- 1st Qu.:10.328   1st Qu.:44.37   1st Qu.:10.328   1st Qu.:44.37   2-Q7825/2-Q7826:  24680  
- Median :11.147   Median :44.51   Median :11.147   Median :44.51   2-P9739/2-P9740:  24670  
- Mean   :10.915   Mean   :44.52   Mean   :10.915   Mean   :44.52   2-Q7935/2-Q7936:  24660  
- 3rd Qu.:11.347   3rd Qu.:44.69   3rd Qu.:11.347   3rd Qu.:44.69   2-Q2081/2-Q2082:  24654  
- Max.   :11.753   Max.   :45.01   Max.   :11.753   Max.   :45.01   2-Q3655/2-Q3656:  24648  
-                                                                   (Other)        :5337575  
- Polarization    ATPCflag         ATPCvalue         Direction             ID       
- H   :1234217   Mode :logical   Min.   :-11       forward:2728159   Min.   :  2.0  
- V   :4032743   FALSE:1055009   1st Qu.: -4       back   :2757412   1st Qu.:161.0  
- NA's: 218611   TRUE :4430562   Median : -2                         Median :359.0  
-                                Mean   : -3                         Mean   :344.5  
-                                3rd Qu.: -2                         3rd Qu.:517.0  
-                                Max.   : -1                         Max.   :713.0  
-                                NA's   :5349675                                    
- - - -
-
-

2. WetDryNearbyLinkApMinMaxRSL

- - - -
# Run R function:   
-StartTime <- proc.time()
-WetDry <- WetDryNearbyLinkApMinMaxRSL(Data=DataPreprocessed,
-                                      CoorSystemInputData=NULL, 
-                                      MinHoursPmin=MinHoursPmin,
-                                      PeriodHoursPmin=PeriodHoursPmin,
-                                      Radius=Radius,
-                                      Step8=Step8, 
-                                      ThresholdMedian=ThresholdMedian,
-                                      ThresholdMedianL=ThresholdMedianL,
-                                      ThresholdNumberLinks=ThresholdNumberLinks, 
-                                      ThresholdWetDry=ThresholdWetDry)
-cat(sprintf("Finished. (%.1f seconds)\n",round((proc.time()-StartTime)[3],digits=1)))  # ~ 3100 s
- - -
Finished. (4087.7 seconds)
- - -
summary(WetDry)
- - -
      Dry               F            
- Min.   :0.00     Min.   :-2511.369  
- 1st Qu.:1.00     1st Qu.:   -5.669  
- Median :1.00     Median :   -0.768  
- Mean   :0.96     Mean   :   -6.304  
- 3rd Qu.:1.00     3rd Qu.:    1.092  
- Max.   :1.00     Max.   :   49.223  
- NA's   :223621   NA's   :5512       
- - - -
-
-

3. RefLevelMinMaxRSL

- - - -
# Run R function:
-StartTime <- proc.time()
-Pref <- RefLevelMinMaxRSL(Data=DataPreprocessed,
-                          Dry=WetDry$Dry,
-                          HoursRefLevel=HoursRefLevel,
-                          PeriodHoursRefLevel=PeriodHoursRefLevel)
-cat(sprintf("Finished. (%.1f seconds)\n",round((proc.time()-StartTime)[3],digits=1))) # ~ 5610 s
- - -
Finished. (7180.0 seconds)
- - -
summary(Pref)
- - -
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
--102.50  -48.00  -44.00  -44.17  -39.50  -21.00  229560 
- - - -
-
-

4. OutlierFilterMinMax

- - - -
# Run R function:
-DataOutlierFiltered <- OutlierFilterMinMaxRSL(Data=DataPreprocessed,
-                                              F=WetDry$F,
-                                              FilterThreshold=FilterThreshold)
-summary(DataOutlierFiltered)
- - -
   Frequency             DateTime            Pmin              Pmax           PathLength     
- Min.   : 6.00   201606290945:    641   Min.   :-108.00   Min.   :-100.00   Min.   : 0.1618  
- 1st Qu.:17.75   201606291015:    641   1st Qu.: -49.00   1st Qu.: -48.00   1st Qu.: 1.9777  
- Median :19.53   201606291030:    641   Median : -44.00   Median : -44.00   Median : 4.0783  
- Mean   :23.38   201606291100:    641   Mean   : -44.92   Mean   : -43.98   Mean   : 5.4344  
- 3rd Qu.:23.05   201606291115:    641   3rd Qu.: -40.00   3rd Qu.: -39.00   3rd Qu.: 7.1872  
- Max.   :42.59   201606291130:    641   Max.   : -21.00   Max.   : -16.00   Max.   :29.7374  
-                 (Other)     :5481725   NA's   :259220                                       
-     XStart           YStart           XEnd             YEnd                   Label        
- Min.   : 9.617   Min.   :44.09   Min.   : 9.617   Min.   :44.09   2-Q6885/2-Q6886:  24684  
- 1st Qu.:10.328   1st Qu.:44.37   1st Qu.:10.328   1st Qu.:44.37   2-Q7825/2-Q7826:  24680  
- Median :11.147   Median :44.51   Median :11.147   Median :44.51   2-P9739/2-P9740:  24670  
- Mean   :10.915   Mean   :44.52   Mean   :10.915   Mean   :44.52   2-Q7935/2-Q7936:  24660  
- 3rd Qu.:11.347   3rd Qu.:44.69   3rd Qu.:11.347   3rd Qu.:44.69   2-Q2081/2-Q2082:  24654  
- Max.   :11.753   Max.   :45.01   Max.   :11.753   Max.   :45.01   2-Q3655/2-Q3656:  24648  
-                                                                   (Other)        :5337575  
- Polarization    ATPCflag         ATPCvalue         Direction             ID       
- H   :1234217   Mode :logical   Min.   :-11       forward:2728159   Min.   :  2.0  
- V   :4032743   FALSE:1055009   1st Qu.: -4       back   :2757412   1st Qu.:161.0  
- NA's: 218611   TRUE :4430562   Median : -2                         Median :359.0  
-                                Mean   : -3                         Mean   :344.5  
-                                3rd Qu.: -2                         3rd Qu.:517.0  
-                                Max.   : -1                         Max.   :713.0  
-                                NA's   :5349675                                    
- - - -
-
-

5. CorrectMinMaxRSL

- - - -
# Run R function:
-Pcor <- CorrectMinMaxRSL(Data=DataOutlierFiltered,
-                         Dry=WetDry$Dry,
-                         Pref=Pref)
-summary(Pcor)
- - -
    PminCor          PmaxCor      
- Min.   :-106.0   Min.   :-102.5  
- 1st Qu.: -48.0   1st Qu.: -48.0  
- Median : -44.0   Median : -44.0  
- Mean   : -44.3   Mean   : -44.2  
- 3rd Qu.: -40.0   3rd Qu.: -39.5  
- Max.   : -21.0   Max.   : -21.0  
- NA's   :478700   NA's   :478700  
- - - -
-
-

6. RainRetrievalMinMaxRSL

- - - -
kRPowerLawDataH <- read.table(FileRainRetrHorizontal)
-colnames(kRPowerLawDataH) <- c("f", "a", "b")
-kRPowerLawDataV <- read.table(FileRainRetrVertical)
-colnames(kRPowerLawDataV) <- c("f", "a", "b")
-# Run R function:
-StartTime <- proc.time()
-Rmean <- RainRetrievalMinMaxRSL(Aa=Aa,
-                                alpha=alpha,
-                                Data=DataOutlierFiltered,
-                                kRPowerLawDataH=kRPowerLawDataH,
-                                kRPowerLawDataV=kRPowerLawDataV,
-                                PmaxCor=Pcor$PmaxCor,
-                                PminCor=Pcor$PminCor,
-                                Pref=Pref)
-cat(sprintf("Finished. (%.1f seconds)\n",round((proc.time()-StartTime)[3],digits=1))) # ~ 20 s
- - -
Finished. (23.3 seconds)
- - -
summary(Rmean)
- - -
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
-    0.0     0.0     0.0     0.1     0.0   208.3  478700 
- - -
hist(log(Rmean))
- - -

- - - -
-
-

Write path-average rainfall data to files:

- - - -
ID <- unique(DataPreprocessed$ID)
-t <- sort(unique(DataPreprocessed$DateTime))
-t_sec <- as.numeric(as.POSIXct(as.character(t), format = "%Y%m%d%H%M"))
-dt <- min(diff(t_sec))
-save(list=ls(), file = "Cmldata_ER2016.RData")
-## merge in a single dataset for analyses
-CmlRainfall                   <- DataPreprocessed
-CmlRainfall$Pref              <- Pref
-CmlRainfall$PminCor           <- Pcor$PminCor
-CmlRainfall$PmaxCor           <- Pcor$PmaxCor
-CmlRainfall$DryClass          <- WetDry$Dry
-CmlRainfall$RainfallMeanInt   <- Rmean
-CmlRainfall$RainfallDepthPath <- Rmean * dt / 3600
-save(CmlRainfall, file = "CmlRainfall_ER2016.RData")
-save(CmlRainfall, file = "CmlRainfall_ER2016v2.RData", version = 2)
-# write.csv(x = CmlRainfall, file = "CmlRainfall_ER2016.csv")
- - - - - - -

rr ## slow write-to-file, use tidyverse::write_delim() instead ToFile = F if (ToFile) {
-# Location of output link data: FolderRainEstimates <- paste(,TIMESTEP,,sep=\)

-

# Create directory for output files: if(!dir.exists(FolderRainEstimates)){ dir.create(FolderRainEstimates) }

-

# Write output to file

-

for (i in 1 : length(t)) { ind <- which(DataPreprocessed\(DateTime == t[i]) int_data <- data.frame(ID = DataPreprocessed\)ID[ind], RainfallDepthPath = Rmean[ind] * dt / 3600, PathLength = DataPreprocessed\(PathLength[ind], XStart = DataPreprocessed\)XStart[ind], YStart = DataPreprocessed\(YStart[ind], XEnd = DataPreprocessed\)XEnd[ind], YEnd = DataPreprocessed\(YEnd[ind], IntervalNumber = rep(i, length(ind)), Frequency = DataPreprocessed\)Frequency[ind])

-
Filename <- paste(FolderRainEstimates, \/linkdata_\, t[i], \.dat\, sep=\\)
-write.table(int_data, Filename, row.names = FALSE, col.names = TRUE, append = FALSE, quote = FALSE)
-

} }

-
- - - -

Note that the output files contain rainfall depths (mm). If these data are to be used for the interpolation, they must first be read (“Interpolation.R” does not read these files). Using the data for “Interpolation.R” requires a conversion from rainfall depth (mm) to rainfall intensity (mm/h).

-
-
-

7. Interpolation

-

Interpolation will be performed for hourly accumulated rainfall, so cumulative sums have to be performed

- - - -
summary(CmlHourlyData)
-
- - -
         DateTime         Frequency       PathLength          XStart           YStart     
- 201606291200:    641   Min.   : 6.00   Min.   : 0.1618   Min.   : 9.617   Min.   :44.09  
- 201606292100:    640   1st Qu.:17.75   1st Qu.: 1.9777   1st Qu.:10.328   1st Qu.:44.37  
- 201606300000:    640   Median :19.42   Median : 4.0783   Median :11.147   Median :44.51  
- 201606300100:    640   Mean   :23.37   Mean   : 5.4384   Mean   :10.915   Mean   :44.52  
- 201606271700:    639   3rd Qu.:23.05   3rd Qu.: 7.1872   3rd Qu.:11.347   3rd Qu.:44.69  
- 201606271800:    639   Max.   :42.59   Max.   :29.7374   Max.   :11.753   Max.   :45.01  
- (Other)     :1354216                                                                     
-      XEnd             YEnd                   Label         Polarization    Direction     
- Min.   : 9.617   Min.   :44.09   2-Q6885/2-Q6886:   6109   H   :305594   forward:675791  
- 1st Qu.:10.328   1st Qu.:44.37   2-Q7825/2-Q7826:   6105   V   :998048   back   :682264  
- Median :11.147   Median :44.51   2-P9739/2-P9740:   6103   NA's: 54413                   
- Mean   :10.915   Mean   :44.52   2-Q2081/2-Q2082:   6097                                 
- 3rd Qu.:11.347   3rd Qu.:44.69   2-Q6581/2-Q6582:   6095                                 
- Max.   :11.753   Max.   :45.01   2-Q7935/2-Q7936:   6093                                 
-                                  (Other)        :1321453                                 
-       ID        HourlyRainfallDepth
- Min.   :  2.0   Min.   :  0.00     
- 1st Qu.:161.0   1st Qu.:  0.00     
- Median :359.0   Median :  0.00     
- Mean   :344.5   Mean   :  0.08     
- 3rd Qu.:517.0   3rd Qu.:  0.00     
- Max.   :713.0   Max.   :109.30     
-                 NA's   :119922     
- - - -

Interpolation over the grid

- - -

Rasters

- - - -

- - - - -
- -
LS0tCnRpdGxlOiAiUkFJTkxJTksgTm90ZWJvb2siCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KVGhlIFJBSU5MSU5LIHBhY2thZ2UuIFJldHJpZXZhbCBhbGdvcml0aG0gZm9yIHJhaW5mYWxsIG1hcHBpbmcgZnJvbSBtaWNyb3dhdmUgbGlua3MKaW4gYSBjZWxsdWxhciBjb21tdW5pY2F0aW9uIG5ldHdvcmsuCgpWZXJzaW9uIDEuMTQKQ29weXJpZ2h0IChDKSAyMDE5IEFhcnQgT3ZlcmVlbQoKVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkKaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkKdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IKKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4KClRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLApidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgpNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUKR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KCllvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlCmFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uCgpOb3RlIHRoYXQgaXQgaXMgbm90IG5lY2Vzc2FyaWx5IGEgcHJvYmxlbSBpZiBhIGZ1bmN0aW9uIGFyZ3VtZW50IGlzIG5vdCBzdXBwbGllZCB0byB0aGUgZnVuY3Rpb24uIElmIHRoZQpmdW5jdGlvbiBhcmd1bWVudCBpcyBub3QgdXNlZCwgdGhlbiB0aGVyZSBpcyBubyBwcm9ibGVtLiBPbmx5IGJlIGF3YXJlIHRoYXQgeW91IHNob3VsZCB1c2UgZS5nLgpNYXhGcmVxdWVuY3k9TWF4RnJlcXVlbmN5LiBJLmUuIGlmIHlvdSBvbmx5IHN1cHBseSBNYXhGcmVxdWVuY3kgYW5kIHRoZSBmdW5jdGlvbiBhcmd1bWVudCBiZWZvcmUKTWF4RnJlcXVlbmN5IGlzIG1pc3NpbmcsIHRoYW4gdGhlIGZ1bmN0aW9uIHdpbGwgbm90IGV4ZWN1dGUgcHJvcGVybHkuCgoKIyAwLiBMb2FkIFIgbGlicmFyaWVzLCBwYXJhbWV0ZXIgdmFsdWVzLCBhbmQgb3RoZXIgc2V0dGluZ3MuClRoaXMgYWxzbyBsb2FkcyB0aGUgUkFJTkxJTksgcGFja2FnZS4gICAgICAgICAgIApgYGB7ciBTZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBybShsaXN0ID0gbHMoKSkKc291cmNlKCJjb25maWcuUiIpIApzb3VyY2UoImZ1bmN0aW9ucy5SIikKYGBgCklmIHRoZSB0aW1lIHpvbmUgb2YgdGhlIGVtcGxveWVkIG1pY3Jvd2F2ZSBsaW5rIGRhdGFzZXQgaXMgbm90IHRoZSBzYW1lIGFzIHRoZSAobG9jYWwpIHRpbWUgem9uZSB1c2VkIGJ5IFIgb24geW91ciBjb21wdXRlciwgc2V0IHRoZSB0aW1lIHpvbmUgb2YgdGhlIG1pY3Jvd2F2ZSBsaW5rIGRhdGFzZXQ6Cih0aGlzIGlzIGltcG9ydGFudCBmb3IgZnVuY3Rpb25zIFJlZkxldmVsTWluTWF4UlNMLCBXZXREcnlOZWFyYnlMaW5rQXBNaW5NYXhSU0wgYW5kIEludGVycG9sYXRpb24pOgpgYGB7cn0KU3lzLnNldGVudihUWj0nVVRDJykKYGBgCgpPdGhlcndpc2UgUkFJTkxJTksgY2FuIGRlcml2ZSBhIHdyb25nIHRpbWUgaW50ZXJ2YWwgbGVuZ3RoIGR1ZSB0byBnb2luZyB0byBvciBmcm9tIGRheWxpZ2h0IHNhdmluZyB0aW1lIChEU1QpLiBUaW1pbmcgb2YgRFNUIG1heSBiZSBkaWZmZXJlbnQgYmV0d2VlbiB0aW1lIHpvbmVzLCBvciBvbmUgdGltZSB6b25lIG1heSBub3QgaGF2ZSBhIGNoYW5nZSB0by9mcm9tIERTVC4KCgoKIyAxLiBQcmVwcm9jZXNzaW5nTWluTWF4UlNMCgpgYGB7ciBEYXRhIGxvYWRpbmd9CgojIExvYWQgZGF0YToKbG9hZCgiZGF0YS9MaW5rZGF0YS5SRGF0YSIpCiMgc3VtbWFyeShMaW5rZGF0YSkKCiMgQWRkIGNvbHVtbiB3aXRoIHBvbGFyaXphdGlvbiBpZiB0aGlzIGNvbHVtbiBpcyBub3Qgc3VwcGxpZWQgaW4gdGhlIGxpbmsgZGF0YToKaWYgKCJQb2xhcml6YXRpb24iICVpbiUgbmFtZXMoTGlua2RhdGEpPT1GQUxTRSkKewogIExpbmtkYXRhJFBvbGFyaXphdGlvbiA8LSByZXAoTkEsbnJvdyhMaW5rZGF0YSkpCn0KYGBgCgpXaGVuIG5vIGluZm9ybWF0aW9uIG9uIHBvbGFyaXphdGlvbiBpcyBwcm92aWRlZCwgdGhlIGFib3ZlIGNvZGUgY3JlYXRlcyBhIGNvbHVtbiBvZiBOQSBmb3IgUG9sYXJpemF0aW9uLiBJbiB0aGUgZnVuY3Rpb24gIlJhaW5SZXRyaWV2YWxNaW5NYXhSU0wuUiIgbGlua3Mgd2l0aApOQSB2YWx1ZXMgZm9yIHBvbGFyaXphdGlvbiBhcmUgcHJvY2Vzc2VkIHdpdGggYSAmIGIgdmFsdWVzIGRldGVybWluZWQgZm9yIHZlcnRpY2FsbHkgcG9sYXJpemVkIHNpZ25hbHMuCklmIGluZm9ybWF0aW9uIG9uIHBvbGFyaXphdGlvbiBvZiBsaW5rcyBpcyBhdmFpbGFibGUsIHVzZSBIIGZvciBob3Jpem9udGFsbHkgcG9sYXJpemVkICYgViBmb3IgdmVydGljYWxseSBwb2xhcml6ZWQgaW4gIkxpbmtkYXRhIFBvbGFyaXphdGlvbiIuCkgsIFYgJiBOQSBtYXkgb2NjdXIgaW4gdGhlIHNhbWUgTGlua2RhdGEgZmlsZS4KCgpgYGB7ciBQcmVwcm9jZXNzaW5nfQojIFJ1biBSIGZ1bmN0aW9uOgpTdGFydFRpbWUgPC0gcHJvYy50aW1lKCkKCkRhdGFQcmVwcm9jZXNzZWQgPC0gUHJlcHJvY2Vzc2luZ01pbk1heFJTTChEYXRhPUxpbmtkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWF4RnJlcXVlbmN5PU1heEZyZXF1ZW5jeSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1pbkZyZXF1ZW5jeT1NaW5GcmVxdWVuY3ksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVRSVUUpCgpjYXQoc3ByaW50ZigiRmluaXNoZWQuICglLjFmIHNlY29uZHMpXG4iLHJvdW5kKChwcm9jLnRpbWUoKS1TdGFydFRpbWUpWzNdLGRpZ2l0cz0xKSkpICMgfiAzNjAgcwoKc3VtbWFyeShEYXRhUHJlcHJvY2Vzc2VkKQoKYGBgCgoKIyAyLiBXZXREcnlOZWFyYnlMaW5rQXBNaW5NYXhSU0wKCmBgYHtyIENsYXNzaWZpY2F0aW9ufQojIFJ1biBSIGZ1bmN0aW9uOgkKU3RhcnRUaW1lIDwtIHByb2MudGltZSgpCgpXZXREcnkgPC0gV2V0RHJ5TmVhcmJ5TGlua0FwTWluTWF4UlNMKERhdGE9RGF0YVByZXByb2Nlc3NlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb29yU3lzdGVtSW5wdXREYXRhPU5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1pbkhvdXJzUG1pbj1NaW5Ib3Vyc1BtaW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUGVyaW9kSG91cnNQbWluPVBlcmlvZEhvdXJzUG1pbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSYWRpdXM9UmFkaXVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0ZXA4PVN0ZXA4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaHJlc2hvbGRNZWRpYW49VGhyZXNob2xkTWVkaWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRocmVzaG9sZE1lZGlhbkw9VGhyZXNob2xkTWVkaWFuTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaHJlc2hvbGROdW1iZXJMaW5rcz1UaHJlc2hvbGROdW1iZXJMaW5rcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGhyZXNob2xkV2V0RHJ5PVRocmVzaG9sZFdldERyeSkKCmNhdChzcHJpbnRmKCJGaW5pc2hlZC4gKCUuMWYgc2Vjb25kcylcbiIscm91bmQoKHByb2MudGltZSgpLVN0YXJ0VGltZSlbM10sZGlnaXRzPTEpKSkgICMgfiAzMTAwIHMKCnN1bW1hcnkoV2V0RHJ5KQpgYGAKCiMgMy4gUmVmTGV2ZWxNaW5NYXhSU0wKCmBgYHtyIFJlZmVyZW5jZSBsZXZlbH0KIyBSdW4gUiBmdW5jdGlvbjoKU3RhcnRUaW1lIDwtIHByb2MudGltZSgpCgpQcmVmIDwtIFJlZkxldmVsTWluTWF4UlNMKERhdGE9RGF0YVByZXByb2Nlc3NlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICBEcnk9V2V0RHJ5JERyeSwKICAgICAgICAgICAgICAgICAgICAgICAgICBIb3Vyc1JlZkxldmVsPUhvdXJzUmVmTGV2ZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgUGVyaW9kSG91cnNSZWZMZXZlbD1QZXJpb2RIb3Vyc1JlZkxldmVsKQoKY2F0KHNwcmludGYoIkZpbmlzaGVkLiAoJS4xZiBzZWNvbmRzKVxuIixyb3VuZCgocHJvYy50aW1lKCktU3RhcnRUaW1lKVszXSxkaWdpdHM9MSkpKSAjIH4gNTYxMCBzCgpzdW1tYXJ5KFByZWYpCmBgYAoKIyA0LiBPdXRsaWVyRmlsdGVyTWluTWF4CmBgYHtyIE91dGxpZXJzIGZpbHRlcn0KIyBSdW4gUiBmdW5jdGlvbjoKRGF0YU91dGxpZXJGaWx0ZXJlZCA8LSBPdXRsaWVyRmlsdGVyTWluTWF4UlNMKERhdGE9RGF0YVByZXByb2Nlc3NlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEY9V2V0RHJ5JEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGaWx0ZXJUaHJlc2hvbGQ9RmlsdGVyVGhyZXNob2xkKQoKc3VtbWFyeShEYXRhT3V0bGllckZpbHRlcmVkKQpgYGAKCiMgNS4gQ29ycmVjdE1pbk1heFJTTAoKYGBge3IgQ29ycmVjdGVkIHBvd2Vyc30KIyBSdW4gUiBmdW5jdGlvbjoKUGNvciA8LSBDb3JyZWN0TWluTWF4UlNMKERhdGE9RGF0YU91dGxpZXJGaWx0ZXJlZCwKICAgICAgICAgICAgICAgICAgICAgICAgIERyeT1XZXREcnkkRHJ5LAogICAgICAgICAgICAgICAgICAgICAgICAgUHJlZj1QcmVmKQoKc3VtbWFyeShQY29yKQpgYGAKCgojIDYuIFJhaW5SZXRyaWV2YWxNaW5NYXhSU0wKCmBgYHtyIFJhaW4gcmV0cml2YWx9CmtSUG93ZXJMYXdEYXRhSCA8LSByZWFkLnRhYmxlKEZpbGVSYWluUmV0ckhvcml6b250YWwpCmNvbG5hbWVzKGtSUG93ZXJMYXdEYXRhSCkgPC0gYygiZiIsICJhIiwgImIiKQoKa1JQb3dlckxhd0RhdGFWIDwtIHJlYWQudGFibGUoRmlsZVJhaW5SZXRyVmVydGljYWwpCmNvbG5hbWVzKGtSUG93ZXJMYXdEYXRhVikgPC0gYygiZiIsICJhIiwgImIiKQoKCiMgUnVuIFIgZnVuY3Rpb246ClN0YXJ0VGltZSA8LSBwcm9jLnRpbWUoKQoKUm1lYW4gPC0gUmFpblJldHJpZXZhbE1pbk1heFJTTChBYT1BYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYT1hbHBoYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEYXRhPURhdGFPdXRsaWVyRmlsdGVyZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga1JQb3dlckxhd0RhdGFIPWtSUG93ZXJMYXdEYXRhSCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrUlBvd2VyTGF3RGF0YVY9a1JQb3dlckxhd0RhdGFWLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBtYXhDb3I9UGNvciRQbWF4Q29yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBtaW5Db3I9UGNvciRQbWluQ29yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByZWY9UHJlZikKCmNhdChzcHJpbnRmKCJGaW5pc2hlZC4gKCUuMWYgc2Vjb25kcylcbiIscm91bmQoKHByb2MudGltZSgpLVN0YXJ0VGltZSlbM10sZGlnaXRzPTEpKSkgIyB+IDIwIHMKCnN1bW1hcnkoUm1lYW4pCmhpc3QobG9nKFJtZWFuKSkKYGBgCgoKIyBXcml0ZSBwYXRoLWF2ZXJhZ2UgcmFpbmZhbGwgZGF0YSB0byBmaWxlczoKCgpgYGB7ciBTYXZlIHRvIFJEYXRhfQpJRCA8LSB1bmlxdWUoRGF0YVByZXByb2Nlc3NlZCRJRCkKdCA8LSBzb3J0KHVuaXF1ZShEYXRhUHJlcHJvY2Vzc2VkJERhdGVUaW1lKSkKdF9zZWMgPC0gYXMubnVtZXJpYyhhcy5QT1NJWGN0KGFzLmNoYXJhY3Rlcih0KSwgZm9ybWF0ID0gIiVZJW0lZCVIJU0iKSkKZHQgPC0gbWluKGRpZmYodF9zZWMpKQpzYXZlKGxpc3Q9bHMoKSwgZmlsZSA9ICJDbWxkYXRhLlJEYXRhIikKCiMjIG1lcmdlIGluIGEgc2luZ2xlIGRhdGFzZXQgZm9yIGFuYWx5c2VzCkNtbFJhaW5mYWxsICAgICAgICAgICAgICAgICAgIDwtIERhdGFQcmVwcm9jZXNzZWQKQ21sUmFpbmZhbGwkUHJlZiAgICAgICAgICAgICAgPC0gUHJlZgpDbWxSYWluZmFsbCRQbWluQ29yICAgICAgICAgICA8LSBQY29yJFBtaW5Db3IKQ21sUmFpbmZhbGwkUG1heENvciAgICAgICAgICAgPC0gUGNvciRQbWF4Q29yCkNtbFJhaW5mYWxsJERyeUNsYXNzICAgICAgICAgIDwtIFdldERyeSREcnkKQ21sUmFpbmZhbGwkUmFpbmZhbGxNZWFuSW50ICAgPC0gUm1lYW4KQ21sUmFpbmZhbGwkUmFpbmZhbGxEZXB0aFBhdGggPC0gUm1lYW4gKiBkdCAvIDM2MDAKCnNhdmUoQ21sUmFpbmZhbGwsIGZpbGUgPSAiQ21sUmFpbmZhbGwuUkRhdGEiKQpzYXZlKENtbFJhaW5mYWxsLCBmaWxlID0gIkNtbFJhaW5mYWxsX3YyLlJEYXRhIiwgdmVyc2lvbiA9IDIpCgojIHdyaXRlLmNzdih4ID0gQ21sUmFpbmZhbGwsIGZpbGUgPSAiQ21sUmFpbmZhbGxfRVIyMDE2LmNzdiIpCmBgYAoKCmBgYHtyIFNhdmUgdG8gZmlsZX0KIyMgc2xvdyB3cml0ZS10by1maWxlLCB1c2UgdGlkeXZlcnNlOjp3cml0ZV9kZWxpbSgpIGluc3RlYWQKVG9GaWxlID0gRgppZiAoVG9GaWxlKQp7CQogICMgTG9jYXRpb24gb2Ygb3V0cHV0IGxpbmsgZGF0YToKICBGb2xkZXJSYWluRXN0aW1hdGVzIDwtIHBhc3RlKCJMaW5rUGF0aFJhaW5EZXB0aHMiLFRJTUVTVEVQLCJtaW4iLHNlcD0iIikKICAKICAjIENyZWF0ZSBkaXJlY3RvcnkgZm9yIG91dHB1dCBmaWxlczoKICBpZighZGlyLmV4aXN0cyhGb2xkZXJSYWluRXN0aW1hdGVzKSl7IGRpci5jcmVhdGUoRm9sZGVyUmFpbkVzdGltYXRlcykgfQogIAogICMgV3JpdGUgb3V0cHV0IHRvIGZpbGUKICAKICBmb3IgKGkgaW4gMSA6IGxlbmd0aCh0KSkKICB7CiAgICBpbmQgPC0gd2hpY2goRGF0YVByZXByb2Nlc3NlZCREYXRlVGltZSA9PSB0W2ldKQogICAgaW50X2RhdGEgPC0gZGF0YS5mcmFtZShJRCA9IERhdGFQcmVwcm9jZXNzZWQkSURbaW5kXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFJhaW5mYWxsRGVwdGhQYXRoID0gUm1lYW5baW5kXSAqIGR0IC8gMzYwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFBhdGhMZW5ndGggPSBEYXRhUHJlcHJvY2Vzc2VkJFBhdGhMZW5ndGhbaW5kXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFhTdGFydCA9IERhdGFQcmVwcm9jZXNzZWQkWFN0YXJ0W2luZF0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICBZU3RhcnQgPSBEYXRhUHJlcHJvY2Vzc2VkJFlTdGFydFtpbmRdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgWEVuZCA9IERhdGFQcmVwcm9jZXNzZWQkWEVuZFtpbmRdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgWUVuZCA9IERhdGFQcmVwcm9jZXNzZWQkWUVuZFtpbmRdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgSW50ZXJ2YWxOdW1iZXIgPSByZXAoaSwgbGVuZ3RoKGluZCkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgRnJlcXVlbmN5ID0gRGF0YVByZXByb2Nlc3NlZCRGcmVxdWVuY3lbaW5kXSkKICAgIAogICAgRmlsZW5hbWUgPC0gcGFzdGUoRm9sZGVyUmFpbkVzdGltYXRlcywgIi9saW5rZGF0YV8iLCB0W2ldLCAiLmRhdCIsIHNlcD0iIikKICAgIHdyaXRlLnRhYmxlKGludF9kYXRhLCBGaWxlbmFtZSwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUsIGFwcGVuZCA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQogIH0KfQpgYGAKTm90ZSB0aGF0IHRoZSBvdXRwdXQgZmlsZXMgY29udGFpbiByYWluZmFsbCBkZXB0aHMgKG1tKS4gSWYgdGhlc2UgZGF0YSBhcmUgdG8gYmUgdXNlZCBmb3IgdGhlIGludGVycG9sYXRpb24sIHRoZXkgbXVzdCBmaXJzdCBiZSByZWFkICgiSW50ZXJwb2xhdGlvbi5SIiBkb2VzIG5vdCByZWFkIHRoZXNlIGZpbGVzKS4KVXNpbmcgdGhlIGRhdGEgZm9yICJJbnRlcnBvbGF0aW9uLlIiIHJlcXVpcmVzIGEgY29udmVyc2lvbiBmcm9tIHJhaW5mYWxsIGRlcHRoIChtbSkgdG8gcmFpbmZhbGwgaW50ZW5zaXR5IChtbS9oKS4KCgojIDcuIEludGVycG9sYXRpb24KSW50ZXJwb2xhdGlvbiB3aWxsIGJlIHBlcmZvcm1lZCBmb3IgaG91cmx5IGFjY3VtdWxhdGVkIHJhaW5mYWxsLCBzbyBjdW11bGF0aXZlIHN1bXMgaGF2ZSB0byBiZSBwZXJmb3JtZWQKYGBge3J9CiMgbG9hZCgiQ21sUmFpbmZhbGxfRVIyMDE2LlJEYXRhIikKCiMgQ29tcHV0ZSBob3VybHkgYWNjdW11bGF0ZWQgcmFpbmZhbGwgYXMgc3VtIG9mIHRoZSAxNW1pbiByYWluZmFsbCBkZXB0aHMKQ21sSG91cmx5RGF0YSA8LSBmYXN0NTB4X2FjY3UxaHIoQ21sUmFpbmZhbGwgPSBDbWxSYWluZmFsbCkKCnNhdmUoQ21sSG91cmx5RGF0YSwgZmlsZSA9ICJIb3VybHlSYWluZmFsbC5SRGF0YSIpCnN1bW1hcnkoQ21sSG91cmx5RGF0YSkKCiMgcGxvdChzMnAoQ21sUmFpbmZhbGwkRGF0ZVRpbWVbMjIwMDAwOjI1MDAwMF0pLCAKIyAgICAgIENtbFJhaW5mYWxsJFJhaW5mYWxsTWVhbkludFsyMjAwMDA6MjUwMDAwXSwgCiMgICAgICBjb2wgPSAicmVkIikgKwojICAgcG9pbnRzKHMycChDbWxIb3VybHlEYXRhJERhdGVUaW1lKSwgCiMgICAgICAgICAgQ21sSG91cmx5RGF0YSRIb3VybHlSYWluZmFsbERlcHRoLCAKIyAgICAgICAgICBwY2ggPSAiKyIpCgpgYGAKCgpJbnRlcnBvbGF0aW9uIG92ZXIgdGhlIGdyaWQKYGBge3IsIGluY2x1ZGU9RkFMU0V9CiMgbG9hZCgiSG91cmx5UmFpbmZhbGxfRVIyMDE2LlJEYXRhIikKCiMgUmVhZCBncmlkIG9udG8gd2hpY2ggZGF0YSBhcmUgaW50ZXJwb2xhdGVkClJhaW5HcmlkIDwtIHJlYWQudGFibGUoRmlsZUdyaWQsIGhlYWRlciA9IFRSVUUsIHNlcD0iLCIpCiMgUG9seUdyaWQgPC0gUG9seUdyaWRHZW4oSW50cEdyaWQgPSBSYWluR3JpZCwgU2F2ZVRvRmlsZSA9IFRSVUUsIEZpbGVOYW1lID0gRmlsZVBvbHlnb25zR3JpZCkKCiMgIyBMb2NhdGlvbiBvZiBvdXRwdXQgbGluayBkYXRhOgpGb2xkZXJSYWluTWFwcyA8LSAiSG91cmx5UmFpbk1hcHMiCgojIFJ1biBSIGZ1bmN0aW9uOgpTdGFydFRpbWUgPC0gcHJvYy50aW1lKCkKClJhaW5GaWVsZHMgPC0gSW50ZXJwb2xhdGlvbihEYXRhID0gQ21sSG91cmx5RGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvb3JTeXN0ZW1JbnB1dERhdGEgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRwID0gaWRwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgSW50cE1ldGhvZCA9IEludHBNZXRob2QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBubWF4ID0gbm1heCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5VR0dFVCA9IE5VR0dFVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJBTkdFID0gUkFOR0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTSUxMID0gU0lMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZhcmlvZ3JhbSA9IFZhcmlvZ3JhbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJhaW5HcmlkID0gUmFpbkdyaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBSbWVhbiA9IENtbEhvdXJseURhdGEkSG91cmx5UmFpbmZhbGxEZXB0aCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIE91dHB1dERpciA9IE5VTEwpICAjIEZvbGRlclJhaW5NYXBzCgpzYXZlKFJhaW5GaWVsZHMsIGZpbGUgPSAiSW50cFJhaW5GaWVsZHMuUkRhdGEiKSAgIyB+IDI0MCBzCgpjYXQoc3ByaW50ZigiRmluaXNoZWQuICglLjFmIHNlY29uZHMpXG4iLHJvdW5kKChwcm9jLnRpbWUoKS1TdGFydFRpbWUpWzNdLGRpZ2l0cz0xKSkpCgoKYGBgCgoKUmFzdGVycwpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBsb2FkKCJIb3VybHlSYWluZmFsbF9FUjIwMTYuUkRhdGEiKQojIGxvYWQoIkludHBSYWluRmllbGRzX0VSMjAxNi5SRGF0YSIpCiMgUmFpbkdyaWQgPC0gcmVhZC50YWJsZShGaWxlR3JpZCwgaGVhZGVyID0gVFJVRSwgc2VwPSIsIikKCiMgZGltZW5zaW9uYWwgY2hlY2tzCnN0b3BpZm5vdChkaW0oUmFpbkZpZWxkcylbMV0gPT0gbGVuZ3RoKHVuaXF1ZShDbWxIb3VybHlEYXRhJERhdGVUaW1lKSkpCnN0b3BpZm5vdChkaW0oUmFpbkZpZWxkcylbMl0gPT0gZGltKFJhaW5HcmlkKVsxXSkKCiMgdGltZXN0cmluZ3MKcm93Lm5hbWVzKFJhaW5GaWVsZHMpIDwtIHNvcnQodW5pcXVlKENtbEhvdXJseURhdGEkRGF0ZVRpbWUpKQoKIyBwcm92aW5jZXMgc2hhcGVmaWxlcwpib3JkZXJzICAgPC0gcmVhZE9HUigiUEFSTUEua21sIikgKyByZWFkT0dSKCJCT0xPR05BLmttbCIpCgoKIyByYWluIG1hcHMKbWFwWFlaIDwtIFJhaW5HcmlkCgpSYWluTWFwcyA8LSByYXN0ZXIoKQpwYiA8LSB0eHRQcm9ncmVzc0JhcihtaW4gPSAwLCBtYXggPSBucm93KFJhaW5GaWVsZHMpLCBzdHlsZSA9IDMpCgpmb3IoaSBpbiAxOm5yb3coUmFpbkZpZWxkcykpewogIG1hcFhZWiRaICAgPC0gUmFpbkZpZWxkc1tpLF0KICByYXN0LmNtbCAgIDwtIHJhc3RlckZyb21YWVoobWFwWFlaLCBkaWdpdHMgPSAyKQogIHByb2plY3Rpb24ocmFzdC5jbWwpIDwtIENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQgK25vX2RlZnMgK2VsbHBzPVdHUzg0ICt0b3dnczg0PTAsMCwwIikKICAjIHBsb3QocmFzdC5jbWwpCiAgUmFpbk1hcHMgPC0gYWRkTGF5ZXIoUmFpbk1hcHMsIHJhc3QuY21sKQogIHNldFR4dFByb2dyZXNzQmFyKHBiLCBpKQp9Cm5hbWVzKFJhaW5NYXBzKSA8LSByb3cubmFtZXMoUmFpbkZpZWxkcykKY2xvc2UocGIpCgojIHNhdmUoUmFpbk1hcHMsIGZpbGUgPSAiSW50cFJhaW5NYXBzLlJEYXRhIikKd3JpdGVSYXN0ZXIoeCA9IFJhaW5NYXBzLCBmaWxlbmFtZSA9ICJJbnRwUmFpbk1hcHMiLCBvdmVyd3JpdGUgPSBUUlVFKQoKIyBwbG90KHJvd1N1bXMoUmFpbkZpZWxkcykpCiMgcGxvdChSYWluTWFwcyRYMjAxNjA1MTEyMzAwKQojIHBsb3QoUmFpbk1hcHMsICJYMjAxNjA1MTEyMzAwIikKcGxvdChtYXNrKFJhaW5NYXBzLGJvcmRlcnMpLCAiWDIwMTYwNTExMjMwMCIsIAogICAgIHpsaW0gPSBjKDAsMjEpLCAKICAgICBjb2xOQSA9ICJncmV5MzMiLAogICAgIGNvbD1jKCIjRkZGRkZGIiwgCiAgICAgICAgICAgY20uY29sb3JzKG4gPSA5LCByZXYgPSBUKVs2OjldLCAKICAgICAgICAgICByYWluYm93KG4gPSAxNixzdGFydCA9IDAuNSwgZW5kID0gMC45LCBzID0gMC43KSwgCiAgICAgICAgICAgInJlZCIpKSAjLCBhZGRmdW4gPSBsaW5lcyhib3JkZXJzKQoKYGBgCgo=
- - - -
- - - - - - - - - - - - - - - -