1 Introduction and Background

The dataset in use today originally stems from the extremely popular real estate website, Zillow. It is a compilation of Zillow’s home value index rankings broken down in a month-by-month and state-by-state manner, beginning in January of 2000 and being most recently updated in September of 2025.

Technically speaking, the dataset’s structure is fairly straightforward. There are 51 variables, with the first day of each month acting as a date object within R in YYYY-MM-DD format, and every state in the nation’s home value index getting its own variable, stored as a double (units are $USD). There are 228 missing values across the dataset, with the vast majority of them coming from North Dakota, Montana, Wyoming and New Mexico.

For my analysis, I will be specifically focusing on the typical home values in the state of New York, and constraining my study to the 15 year time window of January 2010 to January of 2025. I will not be primarily concerned with associative and external exploration as to why the changes in home prices have occurred in the manner which they have. Rather I will be applying a longitudinal perspective and developing a number of time series models with the hope of creating a model that can reliably, based on the historical data at hand, predict future New York home values.

2 Plot of the Data

Below we see a plot of the standard New York home’s value over the past 15 years. From this plot, there is one obvious takeaway that instantly comes to the viewer’s mind. That being, there is a clear, noticeable and approximately consistent increase in home values throughout the duration between January of 2010 and January of 2025. To quantify; the home value index for New York in January of 2025 was about $496,846 per home, while in January of 2010 that same metric was only $267,153. This is a staggering increase of about 85.98%.

Time_Series = ts(TS_Data$NY, frequency = 12, start = c(2010,1))
  # frequency set to 12 since our dataset is composed of years, which are 12-month periods
  # keyword start ensures that the axes on graph below will be accurate, that ts function recognizes that the first observation is the first of 12 of value 2010

# using xaxt = "n" will override the graph's default axis. I want the x intervals to be more frequent than every 5 years
plot((Time_Series/1000), xaxt="n",
     main = "New York State's Home Value Index, 2010 - 2025",
     xlab = "Year",
     ylab = "Value (1000's $USD)")
axis(1,
     at = seq(2010, 2025, by = 1),
     labels = seq(2010, 2025, by = 1))

3 Decomposition Analysis

Before creating time series models of varying sizes and using them to forecast future values, I performed decomposition on the dataset. Decomposition is basically the process of breaking down the makeup of a time series into its different key components. These components being the seasonal patterns, overall trend, and random error (sometimes called remainder) that exist within the data. Below are visuals from two decomposition processes; classical and STL.

3.1 Classical Decomposition

Here is a display of the New York home value index data from 2010 to 2025, post classical decomposition. There are a few noticeable takeaways. Looking at the trend component, we see a clear rise in home values over the 15-year period. This is not surprising, as it was also clearly visible in our original plot above. Regarding seasonality, we see consistent oscillation at approximately the same interval length throughout the dataset. On average throughout the years, New York homes had their highest values in the Fall (~ $340,676) and their lowest in the Spring (~ 332,837). Finally, when it comes to the random error component of the decomposed time series, we see a spike in the remainder’s magnitude after 2020. This can most likely be attributed to the economic uncertainty related to the COVID pandemic.

Classic_Decomp = decompose(Time_Series)
plot(Classic_Decomp)

  Summer = filter(Data, Season == "Summer")
  Fall = filter(Data, Season == "Fall")
  Winter = filter(Data, Season == "Winter")
  Spring = filter(Data, Season == "Spring")
    
  invisible(round(mean(Summer$NY)))
  invisible(round(mean(Fall$NY)))
  invisible(round(mean(Winter$NY)))
  invisible(round(mean(Spring$NY)))

3.2 Seasonal and Trend LOESS (STL) Decomposition

The STL decomposition of the data tells practically the same story of the classical decomposition. The only large difference being that this decomposition shows a much larger magnitude of seasonal oscillation from about 2020 to 2025, while the classical decomposition shows equivalent seasonal oscillation throughout.

Generally speaking, STL decomposition is considered a more robust procedure than its classical counterpart, as STL is more effective in dealing with outliers and non-linearity in data. The STL method uses LOESS (modern locally estimated scatterplot smoothing), while the classical method uses a more basic moving average. That is why we see variation in the seasonality of the data in our STL visual.

Going forward, I used the STL method when formulating the time series models.

STL_Decomp = stl(Time_Series, s.window = 12)
  # the s.window argument essentially tells the stl function how to estimate the seasonal component. Since I put the number 12, that is basically telling the function that every 12 observations (months) the seasonal pattern (year) should be reset to re-estimate for the next series of observations. If I was trying to estimate the seasonal component for summer/fall/winter/spring, I would set s.window = to 3

plot(STL_Decomp,
     main = "STL Decomposition of Time Series")

4 Creating Training and Testing Sets

Since it is bad statistical practice to test a model on the same data which it is trained on, I devoted the data’s ten most recent observations (April of 2024 to January of 2025) for post-creation testing purposes. For the training data, I used R’s runif function to randomly select four sample sizes (n) to assign to each of the four training subsets of the data. All four of the training datasets ended with the observation on March of 2024, and respectively began (n - 1) months after January of 2010. I created the training datasets (1 through 4) in sequential order of descending sample size (set 1 has the most observations, set 2 has the second most, etc…).

After subsetting the data into these four separate training sets, I performed STL decomposition on each one and then forecasted each model’s next ten observations (the same ten which make up the known testing dataset). For each model I used the drift method for forecasting, as the drift accounts for historical increases and decreases in a response variable over time, something that is very prevalent in this dataset.

# Training dataset of 171 observations, most we want to take out is about 30.
# use runif function for random selection, to select four numbers between 1 and 30, our training subsets of the data will go from that randomly selected observation point up to point 171 (March of 2024)
   # sort(round(runif(4, min = 1, max = 30)))
    # Results are 9, 12, 16, 25

Testing_Data = TS_Data[172:181,]

# Training set 1: 
Training_Data1 = TS_Data[9:171, ]

# Training set 2: 
Training_Data2 = TS_Data[12:171, ]

# Training set 3: 
Training_Data3 = TS_Data[16:171, ]

# Training set 4: 
Training_Data4 = TS_Data[25:171, ]


### Now that training and testing subsets of data have been created, make time series objects for each

TS_Train1 = ts(Training_Data1$NY, frequency = 12, start = c(2010, 9))
TS_Train2 = ts(Training_Data2$NY, frequency = 12, start = c(2010, 12))
TS_Train3 = ts(Training_Data3$NY, frequency = 12, start = c(2011, 4))
TS_Train4 = ts(Training_Data4$NY, frequency = 12, start = c(2012, 1))

### going to use the stl() function to decompose each of the training dataset time series objects, then use those decomposed objects for forecasting

STL_Training1 = stl(TS_Train1, s.window = 12)
STL_Training2 = stl(TS_Train2, s.window = 12)
STL_Training3 = stl(TS_Train3, s.window = 12)
STL_Training4 = stl(TS_Train4, s.window = 12)

### Forecast calculations with decomposed training set time series objects

  # Set h = 10 as there is 10 observations in the testing dataset, so we can do a one-to-one comparison between our training forecasts for each time series model and our observed values in the testing dataset (April 2024 to January 2025)
Train_Set1_Forecasts = forecast(STL_Training1, h = 10, method = "rwdrift")
Train_Set2_Forecasts = forecast(STL_Training2, h = 10, method = "rwdrift")
Train_Set3_Forecasts = forecast(STL_Training3, h = 10, method = "rwdrift")
Train_Set4_Forecasts = forecast(STL_Training4, h = 10, method = "rwdrift")

4.1 Examining each Training Set’s Forecasted Values

Below I created both a table to quantify each training set’s forecasts as well as a graph to visualize their performances relative to both one another and the true New York home values provided in the original dataset. As we can see, all of the models underestimated the rise in home values that would take place from August of 2024 to January of 2025.

  # Use the $mean selection to see the forecasted predicted values at particular points
TSMean1 = data.frame(Train_Set1_Forecasts$mean)
  colnames(TSMean1) = "Errors"
TSMean2 = data.frame(Train_Set2_Forecasts$mean)
  colnames(TSMean2) = "Errors"
TSMean3 = data.frame(Train_Set3_Forecasts$mean)
  colnames(TSMean3) = "Errors"
TSMean4 = data.frame(Train_Set4_Forecasts$mean)
  colnames(TSMean4) = "Errors"
Years = data.frame(TS_Data$Date[172:181])

Forecasted_Values = cbind(Years, TSMean1, TSMean2, TSMean3, TSMean4, Testing_Data[,2])
colnames(Forecasted_Values) = c("Date", "TS 1", "TS 2", "TS 3", "TS 4", "True Values")
kable(Forecasted_Values, caption = "Forecasted Values Per Training Set")
Forecasted Values Per Training Set
Date TS 1 TS 2 TS 3 TS 4 True Values
2024-04-01 471873.8 471906.1 471970.9 472416.2 474674.4
2024-05-01 473687.4 473749.5 473884.2 474484.1 478114.6
2024-06-01 475432.6 475524.3 475729.0 476477.5 480880.8
2024-07-01 476944.1 477081.9 477258.2 478134.8 483467.0
2024-08-01 478031.1 478215.0 478421.9 479375.2 486631.5
2024-09-01 478733.7 478963.6 479201.1 480193.7 489556.9
2024-10-01 479461.4 479739.6 480047.0 481079.5 492028.3
2024-11-01 480458.1 480784.5 481130.9 482225.5 493899.7
2024-12-01 481615.7 481990.3 482375.8 483545.4 495692.6
2025-01-01 482804.7 483219.2 483708.2 485002.2 496846.3
List_Of_Dates = as.Date(c("2024-04-01", "2024-05-01", "2024-06-01", "2024-07-01", "2024-08-01", "2024-09-01", "2024-10-01", "2024-11-01", "2024-12-01", "2025-01-01"))

TS1 = data.frame(List_Of_Dates, as.double(TSMean1$Errors))
TS2 = data.frame(List_Of_Dates, as.double(TSMean2$Errors))
TS3 = data.frame(List_Of_Dates, as.double(TSMean3$Errors))
TS4 = data.frame(List_Of_Dates, as.double(TSMean4$Errors))

plot(Testing_Data, col = "blue", lwd = 2,
     main = "Forecasted Vs True New York Home Values \n (August 2024 - January 2025)",
     xlab = "Date",
     ylab = "Value($USD)")
  lines(Testing_Data, col = "blue", lwd = 2)
  lines(TS1, col = "red", lwd = 2)
    points(TS1, col = "red")
  lines(TS2, col = "black", lwd = 2)
    points(TS2, col = "black")
  lines(TS3, col = "green", lwd = 2)
    points(TS3, col = "green")
  lines(TS4, col = "purple", lwd = 2)
    points(TS4, col = "purple")
    legend("topleft",
       legend = c("True Values", "Time Series 1", "Time Series 2",
                  "Time Series 3", "Time Series 4"),
       col = c("blue", "red", "black", "green", "purple"),
       lty = 1, pch = 16, lwd = 2)

4.2 Training Set Forecast Error Analysis

As we saw above, there was a consistent underestimation by each of the training set time series. However, there appeared to be a linear and negative correlation between the sample size of the training set, and that set’s forecasts relative to the true values. Training set 4 had the smallest sample size (beginning at January of 2012) and was the most accurate.

A numeric breakdown of each training sets forecasts’ accuracy is below. The metrics I used were mean error (ME), mean square error (MSE) and mean absolute prediction error (MAPE). As seen in the visuals above, as the sample size of our time series training set decreased, its accuracy increased.

This is likely due to non-linear rise in New York home values, especially from 2018 to 2025. The smaller time series training sets were less influenced by the lesser home values of the early parts of the 2010s.

####### Define Error Objects
TS_Forecasts1_Errors = Testing_Data[,2] - TSMean1
TS_Forecasts2_Errors = Testing_Data[,2] - TSMean2
TS_Forecasts3_Errors = Testing_Data[,2] - TSMean3
TS_Forecasts4_Errors = Testing_Data[,2] - TSMean4

####### ME
TS1_ME = sum(TS_Forecasts1_Errors)/nrow(TS_Forecasts1_Errors)
TS2_ME = sum(TS_Forecasts2_Errors)/nrow(TS_Forecasts2_Errors)
TS3_ME = sum(TS_Forecasts3_Errors)/nrow(TS_Forecasts3_Errors)
TS4_ME = sum(TS_Forecasts4_Errors)/nrow(TS_Forecasts4_Errors)

####### MSE
TS1_MSE = sum(TS_Forecasts1_Errors^2)/nrow(TS_Forecasts1_Errors)
TS2_MSE = sum(TS_Forecasts2_Errors^2)/nrow(TS_Forecasts2_Errors)
TS3_MSE = sum(TS_Forecasts3_Errors^2)/nrow(TS_Forecasts3_Errors)
TS4_MSE = sum(TS_Forecasts4_Errors^2)/nrow(TS_Forecasts4_Errors)

####### MAPE
TS1_MAPE = (sum(abs((TS_Forecasts1_Errors/Testing_Data[,2])*100)))/nrow(TS_Forecasts1_Errors)
TS2_MAPE = (sum(abs((TS_Forecasts2_Errors/Testing_Data[,2])*100)))/nrow(TS_Forecasts2_Errors)
TS3_MAPE = (sum(abs((TS_Forecasts3_Errors/Testing_Data[,2])*100)))/nrow(TS_Forecasts3_Errors)
TS4_MAPE = (sum(abs((TS_Forecasts4_Errors/Testing_Data[,2])*100)))/nrow(TS_Forecasts4_Errors)

##### Table to Visualize
All_MEs = rbind(TS1_ME, TS2_ME, TS3_ME, TS4_ME)
All_MSEs = rbind(TS1_MSE, TS2_MSE, TS3_MSE, TS4_MSE)
All_MAPEs = rbind(TS1_MAPE, TS2_MAPE, TS3_MAPE, TS4_MAPE)

Forecast_Errors = cbind(All_MEs, All_MSEs, All_MAPEs)
colnames(Forecast_Errors) = c("ME", "MSE", "MAPE")
rownames(Forecast_Errors) = c("TS1", "TS2", "TS3", "TS4")
kable(Forecast_Errors, caption = "Model Forecasts' Accuracy Measures")
Model Forecasts’ Accuracy Measures
ME MSE MAPE
TS1 9274.949 102471188 1.891789
TS2 9061.826 97571016 1.848419
TS3 8806.477 92147504 1.796344
TS4 7885.797 75042461 1.608069

5 Conclusion

Ultimately, when looking at New York state’s home values over the past 15 years, forecasting monthly index values via STL-decomposed training sets did not yield particularly accurate results. Despite training our forecast algorithm with the drift method, which is meant to take into account historical increases and decreases, all four of our time series underestimated the true values of New York’s home value index from August of 2024 to January of 2025.

In a future analysis, it would possibly be valuable during the training set process, to widen the scope of sample size selection. Doing so would allow us to see at which point does constraining the time interval of observations for the training data become detrimental. As in this instance, with the maximum number of observations coming out being set to 30, we saw a directly negative relationship between sample size of the training set and forecasts’ accuracy.

LS0tCnRpdGxlOiAiTmV3IFlvcmsgU3RhdGUncyBNb250aGx5IEhvbWUgVmFsdWUgSW5kZXggKFNpbmNlIDIwMTApIgphdXRob3I6ICJDaHJpcyBCYWhtIgpkYXRlOiAiMjAyNS0xMS0yMSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgZmlnX3dpZHRoOiA2CiAgICBmaWdfaGVpZ2h0OiA0CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBsdW1lbgogICAgaGlnaGxpZ2h0OiB0YW5nbwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0Ci0tLQoKYGBge2NzcywgZWNobyA9IEZBTFNFfQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOwogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOwogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsKICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsKfQoKaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8KICBmb250LXNpemU6IDI0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDIwcHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTZweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTRweDsKICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsKICBjb250ZW50OiAiLiI7Cn0KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IAojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4KCmlmICghcmVxdWlyZSgia25pdHIiKSkgeyAgICAgICAgICAgICAgICAgICAgICAjIHVzZSBjb25kaXRpb25hbCBzdGF0ZW1lbnQgdG8gZGV0ZWN0CiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikgICAgICAgICAgICAgICAgICAjIHdoZXRoZXIgYSBwYWNrYWdlIHdhcyBpbnN0YWxsZWQgaW4KICAgbGlicmFyeShrbml0cikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91ciBtYWNoaW5lLiBJZiBub3QsIGluc3RhbGwgaXQgYW5kCn0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGxvYWQgaXQgdG8gdGhlIHdvcmtpbmcgZGlyZWN0b3J5LgoKaWYgKCFyZXF1aXJlKHRpZHl2ZXJzZSkpIHtsaWJyYXJ5KHRpZHl2c2Vyc2UpfSAKCmlmICghcmVxdWlyZShHR2FsbHkpKSB7bGlicmFyeShHR2FsbHkpfSAKCmlmICghcmVxdWlyZShrYWJsZUV4dHJhKSkge2xpYnJhcnkoa2FibGVFeHRyYSl9IAoKaWYgKCFyZXF1aXJlKGdncGxvdDIpKSB7bGlicmFyeShnZ3Bsb3QyKX0gCgppZiAoIXJlcXVpcmUoY2FyKSkge2xpYnJhcnkoY2FyKX0gCgppZiAoIXJlcXVpcmUoZHBseXIpKSB7bGlicmFyeShkcGx5cil9IAoKaWYgKCFyZXF1aXJlKHBhbmRlcikpIHtsaWJyYXJ5KHBhbmRlcil9IAoKaWYgKCFyZXF1aXJlKGZvcmVjYXN0KSkge2xpYnJhcnkoZm9yZWNhc3QpfSAKCmlmICghcmVxdWlyZShsdWJyaWRhdGUpKSB7bGlicmFyeShsdWJyaWRhdGUpfSAKCmlmICghcmVxdWlyZSgic2NhbGVzIikpIHsKaW5zdGFsbC5wYWNrYWdlcygic2NhbGVzIikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmxpYnJhcnkoInNjYWxlcyIpIAp9Cgprbml0cjo6b3B0c19jaHVuayRzZXQoCgllY2hvID0gVFJVRSwKCW1lc3NhZ2UgPSBGQUxTRSwKCXdhcm5pbmcgPSBGQUxTRSwKCWNvbW1lbnQgPSBOQSwKCXJlc3VsdHMgPSBUUlVFCikKYGBgCgojIEludHJvZHVjdGlvbiBhbmQgQmFja2dyb3VuZCAKVGhlIGRhdGFzZXQgaW4gdXNlIHRvZGF5IG9yaWdpbmFsbHkgc3RlbXMgZnJvbSB0aGUgZXh0cmVtZWx5IHBvcHVsYXIgcmVhbCBlc3RhdGUgd2Vic2l0ZSwgWmlsbG93LiBJdCBpcyBhIGNvbXBpbGF0aW9uIG9mIFppbGxvdydzIGhvbWUgdmFsdWUgaW5kZXggcmFua2luZ3MgYnJva2VuIGRvd24gaW4gYSBtb250aC1ieS1tb250aCBhbmQgc3RhdGUtYnktc3RhdGUgbWFubmVyLCBiZWdpbm5pbmcgaW4gSmFudWFyeSBvZiAyMDAwIGFuZCBiZWluZyBtb3N0IHJlY2VudGx5IHVwZGF0ZWQgaW4gU2VwdGVtYmVyIG9mIDIwMjUuCgpUZWNobmljYWxseSBzcGVha2luZywgdGhlIGRhdGFzZXQncyBzdHJ1Y3R1cmUgaXMgZmFpcmx5IHN0cmFpZ2h0Zm9yd2FyZC4gVGhlcmUgYXJlIDUxIHZhcmlhYmxlcywgd2l0aCB0aGUgZmlyc3QgZGF5IG9mIGVhY2ggbW9udGggYWN0aW5nIGFzIGEgZGF0ZSBvYmplY3Qgd2l0aGluIFIgaW4gWVlZWS1NTS1ERCBmb3JtYXQsIGFuZCBldmVyeSBzdGF0ZSBpbiB0aGUgbmF0aW9uJ3MgaG9tZSB2YWx1ZSBpbmRleCBnZXR0aW5nIGl0cyBvd24gdmFyaWFibGUsIHN0b3JlZCBhcyBhIGRvdWJsZSAqKih1bml0cyBhcmUgJFVTRCkqKi4gVGhlcmUgYXJlIDIyOCBtaXNzaW5nIHZhbHVlcyBhY3Jvc3MgdGhlIGRhdGFzZXQsIHdpdGggdGhlIHZhc3QgbWFqb3JpdHkgb2YgdGhlbSBjb21pbmcgZnJvbSBOb3J0aCBEYWtvdGEsIE1vbnRhbmEsIFd5b21pbmcgYW5kIE5ldyBNZXhpY28uCgpGb3IgbXkgYW5hbHlzaXMsIEkgd2lsbCBiZSBzcGVjaWZpY2FsbHkgZm9jdXNpbmcgb24gdGhlIHR5cGljYWwgaG9tZSB2YWx1ZXMgaW4gdGhlIHN0YXRlIG9mIE5ldyBZb3JrLCBhbmQgY29uc3RyYWluaW5nIG15IHN0dWR5IHRvIHRoZSAxNSB5ZWFyIHRpbWUgd2luZG93IG9mIEphbnVhcnkgMjAxMCB0byBKYW51YXJ5IG9mIDIwMjUuIEkgd2lsbCBub3QgYmUgcHJpbWFyaWx5IGNvbmNlcm5lZCB3aXRoIGFzc29jaWF0aXZlIGFuZCBleHRlcm5hbCBleHBsb3JhdGlvbiBhcyB0byAqd2h5KiB0aGUgY2hhbmdlcyBpbiBob21lIHByaWNlcyBoYXZlIG9jY3VycmVkIGluIHRoZSBtYW5uZXIgd2hpY2ggdGhleSBoYXZlLiBSYXRoZXIgSSB3aWxsIGJlIGFwcGx5aW5nIGEgbG9uZ2l0dWRpbmFsIHBlcnNwZWN0aXZlIGFuZCBkZXZlbG9waW5nIGEgbnVtYmVyIG9mIHRpbWUgc2VyaWVzIG1vZGVscyB3aXRoIHRoZSBob3BlIG9mIGNyZWF0aW5nIGEgbW9kZWwgdGhhdCBjYW4gcmVsaWFibHksIGJhc2VkIG9uIHRoZSBoaXN0b3JpY2FsIGRhdGEgYXQgaGFuZCwgcHJlZGljdCBmdXR1cmUgTmV3IFlvcmsgaG9tZSB2YWx1ZXMuCgpgYGB7ciBEYXRhIExvYWRpbmcgYW5kIENsZWFuaW5nLCBpbmNsdWRlPUZBTFNFfQpEYXRhX1VybD0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DaHJpc0IyMzIzL1NUQTMyMS9yZWZzL2hlYWRzL21haW4vWmlsbG93X0RhdGEuY3N2IgoKT3JpZ2luYWxfRGF0YSA9IHJlYWRfZGVsaW0oRGF0YV9VcmwsIGRlbGltID0gIiwiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQpzdW0oaXMubmEoT3JpZ2luYWxfRGF0YSkpICMgPSAyMjggbWlzc2luZyB2YWx1ZXMKCiAgIyBCcmVha2Rvd24gb2YgbWlzc2luZyB2YWx1ZXMgcGVyIHN0YXRlCmNvbFN1bXMoaXMubmEoT3JpZ2luYWxfRGF0YSkpW2NvbFN1bXMoaXMubmEoT3JpZ2luYWxfRGF0YSkpID4gMF0KCiMgV2lsbCB1c2UgdGhlIGxhc3QgMTUgeWVhcnMgb2YgZGF0YSwgMTUgeWVhcnMgKiAxMiBtb250aHMgPSAxODAgb2JzZXJ2YXRpb25zCgpEYXRhID0gT3JpZ2luYWxfRGF0YVsxMjE6MzAxLF0KY29sbmFtZXMoRGF0YSlbMV0gPSAiRGF0ZSIKZ2xpbXBzZShEYXRhKQogICMgQWxsIHZhcmlhYmxlcyBmb3JtYXR0ZWQgcmlnaHQsIE1vbnRoIGlzIGRhdGUgb2JqZWN0IGFuZCB0aGUgcmVzdCBhcmUgZG91YmxlcwoKICAjIEdvaW5nIHRvIGNvbmR1Y3QgdW5pdmFyaWF0ZSBhbmFseXNpcywgd2l0aCBOZXcgWW9yaydzIGF2ZXJhZ2UgaG9tZSB2YWx1ZSBpbmRleCAoaW4gJFVTRCkgYXMgdGhlIHJlc3BvbnNlIGluIHRoaXMgdGltZSBzZXJpZXMKCkRhdGEgPSBEYXRhWyAsYygiRGF0ZSIsICJOZXcgWW9yayIpXQpjb2xuYW1lcyhEYXRhKVsyXSA9ICJOWSIKICAjIF4gRm9yIGNvZGluZyBjb252ZW5pZW5jZQoKIyBXYW50IHRvIGxhYmVsIG15IGRhdGEgYnkgbW9udGgsIHNlYXNvbiBhbmQgeWVhci4KICAjIFVzZWQgQUkgZm9yIHNlYXNvbiBhc3NpZ25tZW50IGJlbG93CkRhdGEgPSBEYXRhICU+JQogIG11dGF0ZSgKICAgIFllYXIgPSB5ZWFyKERhdGUpLAogICAgTW9udGggPSBtb250aChEYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKSwKICAgIFNlYXNvbiA9IGNhc2Vfd2hlbigKICAgICAgbW9udGgoRGF0ZSkgJWluJSBjKDEyLCAxLCAyKSB+ICJXaW50ZXIiLAogICAgICBtb250aChEYXRlKSAlaW4lIGMoMywgNCwgNSkgIH4gIlNwcmluZyIsCiAgICAgIG1vbnRoKERhdGUpICVpbiUgYyg2LCA3LCA4KSAgfiAiU3VtbWVyIiwKICAgICAgbW9udGgoRGF0ZSkgJWluJSBjKDksIDEwLCAxMSkgfiAiRmFsbCIKICAgICkKICApCgpUU19EYXRhID0gRGF0YVssMToyXQpgYGAKCiMgUGxvdCBvZiB0aGUgRGF0YQpCZWxvdyB3ZSBzZWUgYSBwbG90IG9mIHRoZSBzdGFuZGFyZCBOZXcgWW9yayBob21lJ3MgdmFsdWUgb3ZlciB0aGUgcGFzdCAxNSB5ZWFycy4gRnJvbSB0aGlzIHBsb3QsIHRoZXJlIGlzIG9uZSBvYnZpb3VzIHRha2Vhd2F5IHRoYXQgaW5zdGFudGx5IGNvbWVzIHRvIHRoZSB2aWV3ZXIncyBtaW5kLiBUaGF0IGJlaW5nLCB0aGVyZSBpcyBhIGNsZWFyLCBub3RpY2VhYmxlIGFuZCBhcHByb3hpbWF0ZWx5IGNvbnNpc3RlbnQgaW5jcmVhc2UgaW4gaG9tZSB2YWx1ZXMgdGhyb3VnaG91dCB0aGUgZHVyYXRpb24gYmV0d2VlbiBKYW51YXJ5IG9mIDIwMTAgYW5kIEphbnVhcnkgb2YgMjAyNS4gVG8gcXVhbnRpZnk7IHRoZSBob21lIHZhbHVlIGluZGV4IGZvciBOZXcgWW9yayBpbiBKYW51YXJ5IG9mIDIwMjUgd2FzIGFib3V0ICQ0OTYsODQ2IHBlciBob21lLCB3aGlsZSBpbiBKYW51YXJ5IG9mIDIwMTAgdGhhdCBzYW1lIG1ldHJpYyB3YXMgb25seSAkMjY3LDE1My4gVGhpcyBpcyBhIHN0YWdnZXJpbmcgaW5jcmVhc2Ugb2YgYWJvdXQgYHIgcm91bmQoKCgoNDk2ODQ2IC0gMjY3MTUzKS8yNjcxNTMpICogMTAwKSwgMilgJS4gCmBgYHtyLCBmaWcuYWxpZ24gPSdjZW50ZXInfQpUaW1lX1NlcmllcyA9IHRzKFRTX0RhdGEkTlksIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IGMoMjAxMCwxKSkKICAjIGZyZXF1ZW5jeSBzZXQgdG8gMTIgc2luY2Ugb3VyIGRhdGFzZXQgaXMgY29tcG9zZWQgb2YgeWVhcnMsIHdoaWNoIGFyZSAxMi1tb250aCBwZXJpb2RzCiAgIyBrZXl3b3JkIHN0YXJ0IGVuc3VyZXMgdGhhdCB0aGUgYXhlcyBvbiBncmFwaCBiZWxvdyB3aWxsIGJlIGFjY3VyYXRlLCB0aGF0IHRzIGZ1bmN0aW9uIHJlY29nbml6ZXMgdGhhdCB0aGUgZmlyc3Qgb2JzZXJ2YXRpb24gaXMgdGhlIGZpcnN0IG9mIDEyIG9mIHZhbHVlIDIwMTAKCiMgdXNpbmcgeGF4dCA9ICJuIiB3aWxsIG92ZXJyaWRlIHRoZSBncmFwaCdzIGRlZmF1bHQgYXhpcy4gSSB3YW50IHRoZSB4IGludGVydmFscyB0byBiZSBtb3JlIGZyZXF1ZW50IHRoYW4gZXZlcnkgNSB5ZWFycwpwbG90KChUaW1lX1Nlcmllcy8xMDAwKSwgeGF4dD0ibiIsCiAgICAgbWFpbiA9ICJOZXcgWW9yayBTdGF0ZSdzIEhvbWUgVmFsdWUgSW5kZXgsIDIwMTAgLSAyMDI1IiwKICAgICB4bGFiID0gIlllYXIiLAogICAgIHlsYWIgPSAiVmFsdWUgKDEwMDAncyAkVVNEKSIpCmF4aXMoMSwKICAgICBhdCA9IHNlcSgyMDEwLCAyMDI1LCBieSA9IDEpLAogICAgIGxhYmVscyA9IHNlcSgyMDEwLCAyMDI1LCBieSA9IDEpKQpgYGAKCgojIERlY29tcG9zaXRpb24gQW5hbHlzaXMKQmVmb3JlIGNyZWF0aW5nIHRpbWUgc2VyaWVzIG1vZGVscyBvZiB2YXJ5aW5nIHNpemVzIGFuZCB1c2luZyB0aGVtIHRvIGZvcmVjYXN0IGZ1dHVyZSB2YWx1ZXMsIEkgcGVyZm9ybWVkIGRlY29tcG9zaXRpb24gb24gdGhlIGRhdGFzZXQuIERlY29tcG9zaXRpb24gaXMgYmFzaWNhbGx5IHRoZSBwcm9jZXNzIG9mIGJyZWFraW5nIGRvd24gdGhlIG1ha2V1cCBvZiBhIHRpbWUgc2VyaWVzIGludG8gaXRzIGRpZmZlcmVudCBrZXkgY29tcG9uZW50cy4gVGhlc2UgY29tcG9uZW50cyBiZWluZyB0aGUgc2Vhc29uYWwgcGF0dGVybnMsIG92ZXJhbGwgdHJlbmQsIGFuZCByYW5kb20gZXJyb3IgKHNvbWV0aW1lcyBjYWxsZWQgcmVtYWluZGVyKSB0aGF0IGV4aXN0IHdpdGhpbiB0aGUgZGF0YS4gQmVsb3cgYXJlIHZpc3VhbHMgZnJvbSB0d28gZGVjb21wb3NpdGlvbiBwcm9jZXNzZXM7IGNsYXNzaWNhbCBhbmQgU1RMLgoKIyMgQ2xhc3NpY2FsIERlY29tcG9zaXRpb24KSGVyZSBpcyBhIGRpc3BsYXkgb2YgdGhlIE5ldyBZb3JrIGhvbWUgdmFsdWUgaW5kZXggZGF0YSBmcm9tIDIwMTAgdG8gMjAyNSwgcG9zdCBjbGFzc2ljYWwgZGVjb21wb3NpdGlvbi4gVGhlcmUgYXJlIGEgZmV3IG5vdGljZWFibGUgdGFrZWF3YXlzLiBMb29raW5nIGF0IHRoZSB0cmVuZCBjb21wb25lbnQsIHdlIHNlZSBhIGNsZWFyIHJpc2UgaW4gaG9tZSB2YWx1ZXMgb3ZlciB0aGUgMTUteWVhciBwZXJpb2QuIFRoaXMgaXMgbm90IHN1cnByaXNpbmcsIGFzIGl0IHdhcyBhbHNvIGNsZWFybHkgdmlzaWJsZSBpbiBvdXIgb3JpZ2luYWwgcGxvdCBhYm92ZS4gUmVnYXJkaW5nIHNlYXNvbmFsaXR5LCB3ZSBzZWUgY29uc2lzdGVudCBvc2NpbGxhdGlvbiBhdCBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIGludGVydmFsIGxlbmd0aCB0aHJvdWdob3V0IHRoZSBkYXRhc2V0LiBPbiBhdmVyYWdlIHRocm91Z2hvdXQgdGhlIHllYXJzLCBOZXcgWW9yayBob21lcyBoYWQgdGhlaXIgaGlnaGVzdCB2YWx1ZXMgaW4gdGhlIEZhbGwgKH4gJDM0MCw2NzYpIGFuZCB0aGVpciBsb3dlc3QgaW4gdGhlIFNwcmluZyAofiAzMzIsODM3KS4gRmluYWxseSwgd2hlbiBpdCBjb21lcyB0byB0aGUgcmFuZG9tIGVycm9yIGNvbXBvbmVudCBvZiB0aGUgZGVjb21wb3NlZCB0aW1lIHNlcmllcywgd2Ugc2VlIGEgc3Bpa2UgaW4gdGhlIHJlbWFpbmRlcidzIG1hZ25pdHVkZSBhZnRlciAyMDIwLiBUaGlzIGNhbiBtb3N0IGxpa2VseSBiZSBhdHRyaWJ1dGVkIHRvIHRoZSBlY29ub21pYyB1bmNlcnRhaW50eSByZWxhdGVkIHRvIHRoZSBDT1ZJRCBwYW5kZW1pYy4KYGBge3IsIGZpZy5hbGlnbiA9J2NlbnRlcid9CkNsYXNzaWNfRGVjb21wID0gZGVjb21wb3NlKFRpbWVfU2VyaWVzKQpwbG90KENsYXNzaWNfRGVjb21wKQoKICBTdW1tZXIgPSBmaWx0ZXIoRGF0YSwgU2Vhc29uID09ICJTdW1tZXIiKQogIEZhbGwgPSBmaWx0ZXIoRGF0YSwgU2Vhc29uID09ICJGYWxsIikKICBXaW50ZXIgPSBmaWx0ZXIoRGF0YSwgU2Vhc29uID09ICJXaW50ZXIiKQogIFNwcmluZyA9IGZpbHRlcihEYXRhLCBTZWFzb24gPT0gIlNwcmluZyIpCiAgICAKICBpbnZpc2libGUocm91bmQobWVhbihTdW1tZXIkTlkpKSkKICBpbnZpc2libGUocm91bmQobWVhbihGYWxsJE5ZKSkpCiAgaW52aXNpYmxlKHJvdW5kKG1lYW4oV2ludGVyJE5ZKSkpCiAgaW52aXNpYmxlKHJvdW5kKG1lYW4oU3ByaW5nJE5ZKSkpCmBgYAoKIyMgU2Vhc29uYWwgYW5kIFRyZW5kIExPRVNTIChTVEwpIERlY29tcG9zaXRpb24KVGhlIFNUTCBkZWNvbXBvc2l0aW9uIG9mIHRoZSBkYXRhIHRlbGxzIHByYWN0aWNhbGx5IHRoZSBzYW1lIHN0b3J5IG9mIHRoZSBjbGFzc2ljYWwgZGVjb21wb3NpdGlvbi4gVGhlIG9ubHkgbGFyZ2UgZGlmZmVyZW5jZSBiZWluZyB0aGF0IHRoaXMgZGVjb21wb3NpdGlvbiBzaG93cyBhIG11Y2ggbGFyZ2VyIG1hZ25pdHVkZSBvZiBzZWFzb25hbCBvc2NpbGxhdGlvbiBmcm9tIGFib3V0IDIwMjAgdG8gMjAyNSwgd2hpbGUgdGhlIGNsYXNzaWNhbCBkZWNvbXBvc2l0aW9uIHNob3dzIGVxdWl2YWxlbnQgc2Vhc29uYWwgb3NjaWxsYXRpb24gdGhyb3VnaG91dC4KCkdlbmVyYWxseSBzcGVha2luZywgU1RMIGRlY29tcG9zaXRpb24gaXMgY29uc2lkZXJlZCBhIG1vcmUgcm9idXN0IHByb2NlZHVyZSB0aGFuIGl0cyBjbGFzc2ljYWwgY291bnRlcnBhcnQsIGFzIFNUTCBpcyBtb3JlIGVmZmVjdGl2ZSBpbiBkZWFsaW5nIHdpdGggb3V0bGllcnMgYW5kIG5vbi1saW5lYXJpdHkgaW4gZGF0YS4gVGhlIFNUTCBtZXRob2QgdXNlcyBMT0VTUyAobW9kZXJuIGxvY2FsbHkgZXN0aW1hdGVkIHNjYXR0ZXJwbG90IHNtb290aGluZyksIHdoaWxlIHRoZSBjbGFzc2ljYWwgbWV0aG9kIHVzZXMgYSBtb3JlIGJhc2ljIG1vdmluZyBhdmVyYWdlLiBUaGF0IGlzIHdoeSB3ZSBzZWUgdmFyaWF0aW9uIGluIHRoZSBzZWFzb25hbGl0eSBvZiB0aGUgZGF0YSBpbiBvdXIgU1RMIHZpc3VhbC4KCkdvaW5nIGZvcndhcmQsIEkgdXNlZCB0aGUgU1RMIG1ldGhvZCB3aGVuIGZvcm11bGF0aW5nIHRoZSB0aW1lIHNlcmllcyBtb2RlbHMuCgpgYGB7ciwgZmlnLmFsaWduID0nY2VudGVyJ30KU1RMX0RlY29tcCA9IHN0bChUaW1lX1Nlcmllcywgcy53aW5kb3cgPSAxMikKICAjIHRoZSBzLndpbmRvdyBhcmd1bWVudCBlc3NlbnRpYWxseSB0ZWxscyB0aGUgc3RsIGZ1bmN0aW9uIGhvdyB0byBlc3RpbWF0ZSB0aGUgc2Vhc29uYWwgY29tcG9uZW50LiBTaW5jZSBJIHB1dCB0aGUgbnVtYmVyIDEyLCB0aGF0IGlzIGJhc2ljYWxseSB0ZWxsaW5nIHRoZSBmdW5jdGlvbiB0aGF0IGV2ZXJ5IDEyIG9ic2VydmF0aW9ucyAobW9udGhzKSB0aGUgc2Vhc29uYWwgcGF0dGVybiAoeWVhcikgc2hvdWxkIGJlIHJlc2V0IHRvIHJlLWVzdGltYXRlIGZvciB0aGUgbmV4dCBzZXJpZXMgb2Ygb2JzZXJ2YXRpb25zLiBJZiBJIHdhcyB0cnlpbmcgdG8gZXN0aW1hdGUgdGhlIHNlYXNvbmFsIGNvbXBvbmVudCBmb3Igc3VtbWVyL2ZhbGwvd2ludGVyL3NwcmluZywgSSB3b3VsZCBzZXQgcy53aW5kb3cgPSB0byAzCgpwbG90KFNUTF9EZWNvbXAsCiAgICAgbWFpbiA9ICJTVEwgRGVjb21wb3NpdGlvbiBvZiBUaW1lIFNlcmllcyIpCmBgYAoKIyBDcmVhdGluZyBUcmFpbmluZyBhbmQgVGVzdGluZyBTZXRzClNpbmNlIGl0IGlzIGJhZCBzdGF0aXN0aWNhbCBwcmFjdGljZSB0byB0ZXN0IGEgbW9kZWwgb24gdGhlIHNhbWUgZGF0YSB3aGljaCBpdCBpcyB0cmFpbmVkIG9uLCBJIGRldm90ZWQgdGhlIGRhdGEncyB0ZW4gbW9zdCByZWNlbnQgb2JzZXJ2YXRpb25zIChBcHJpbCBvZiAyMDI0IHRvIEphbnVhcnkgb2YgMjAyNSkgZm9yIHBvc3QtY3JlYXRpb24gdGVzdGluZyBwdXJwb3Nlcy4gRm9yIHRoZSB0cmFpbmluZyBkYXRhLCBJIHVzZWQgUidzIHJ1bmlmIGZ1bmN0aW9uIHRvIHJhbmRvbWx5IHNlbGVjdCBmb3VyIHNhbXBsZSBzaXplcyAoKm4qKSB0byBhc3NpZ24gdG8gZWFjaCBvZiB0aGUgZm91ciB0cmFpbmluZyBzdWJzZXRzIG9mIHRoZSBkYXRhLiBBbGwgZm91ciBvZiB0aGUgdHJhaW5pbmcgZGF0YXNldHMgZW5kZWQgd2l0aCB0aGUgb2JzZXJ2YXRpb24gb24gTWFyY2ggb2YgMjAyNCwgYW5kIHJlc3BlY3RpdmVseSBiZWdhbiAoKm4qIC0gMSkgbW9udGhzIGFmdGVyIEphbnVhcnkgb2YgMjAxMC4gSSBjcmVhdGVkIHRoZSB0cmFpbmluZyBkYXRhc2V0cyAoMSB0aHJvdWdoIDQpIGluIHNlcXVlbnRpYWwgb3JkZXIgb2YgZGVzY2VuZGluZyBzYW1wbGUgc2l6ZSAoc2V0IDEgaGFzIHRoZSBtb3N0IG9ic2VydmF0aW9ucywgc2V0IDIgaGFzIHRoZSBzZWNvbmQgbW9zdCwgZXRjLi4uKS4KCkFmdGVyIHN1YnNldHRpbmcgdGhlIGRhdGEgaW50byB0aGVzZSBmb3VyIHNlcGFyYXRlIHRyYWluaW5nIHNldHMsIEkgcGVyZm9ybWVkIFNUTCBkZWNvbXBvc2l0aW9uIG9uIGVhY2ggb25lIGFuZCB0aGVuIGZvcmVjYXN0ZWQgZWFjaCBtb2RlbCdzIG5leHQgdGVuIG9ic2VydmF0aW9ucyAodGhlIHNhbWUgdGVuIHdoaWNoIG1ha2UgdXAgdGhlIGtub3duIHRlc3RpbmcgZGF0YXNldCkuIEZvciBlYWNoIG1vZGVsIEkgdXNlZCB0aGUgZHJpZnQgbWV0aG9kIGZvciBmb3JlY2FzdGluZywgYXMgdGhlIGRyaWZ0IGFjY291bnRzIGZvciBoaXN0b3JpY2FsIGluY3JlYXNlcyBhbmQgZGVjcmVhc2VzIGluIGEgcmVzcG9uc2UgdmFyaWFibGUgb3ZlciB0aW1lLCBzb21ldGhpbmcgdGhhdCBpcyB2ZXJ5IHByZXZhbGVudCBpbiB0aGlzIGRhdGFzZXQuCmBgYHtyLCBNYWtpbmcgVHJhaW5pbmcgU2V0c30KIyBUcmFpbmluZyBkYXRhc2V0IG9mIDE3MSBvYnNlcnZhdGlvbnMsIG1vc3Qgd2Ugd2FudCB0byB0YWtlIG91dCBpcyBhYm91dCAzMC4KIyB1c2UgcnVuaWYgZnVuY3Rpb24gZm9yIHJhbmRvbSBzZWxlY3Rpb24sIHRvIHNlbGVjdCBmb3VyIG51bWJlcnMgYmV0d2VlbiAxIGFuZCAzMCwgb3VyIHRyYWluaW5nIHN1YnNldHMgb2YgdGhlIGRhdGEgd2lsbCBnbyBmcm9tIHRoYXQgcmFuZG9tbHkgc2VsZWN0ZWQgb2JzZXJ2YXRpb24gcG9pbnQgdXAgdG8gcG9pbnQgMTcxIChNYXJjaCBvZiAyMDI0KQogICAjIHNvcnQocm91bmQocnVuaWYoNCwgbWluID0gMSwgbWF4ID0gMzApKSkKICAgICMgUmVzdWx0cyBhcmUgOSwgMTIsIDE2LCAyNQoKVGVzdGluZ19EYXRhID0gVFNfRGF0YVsxNzI6MTgxLF0KCiMgVHJhaW5pbmcgc2V0IDE6IApUcmFpbmluZ19EYXRhMSA9IFRTX0RhdGFbOToxNzEsIF0KCiMgVHJhaW5pbmcgc2V0IDI6IApUcmFpbmluZ19EYXRhMiA9IFRTX0RhdGFbMTI6MTcxLCBdCgojIFRyYWluaW5nIHNldCAzOiAKVHJhaW5pbmdfRGF0YTMgPSBUU19EYXRhWzE2OjE3MSwgXQoKIyBUcmFpbmluZyBzZXQgNDogClRyYWluaW5nX0RhdGE0ID0gVFNfRGF0YVsyNToxNzEsIF0KCgojIyMgTm93IHRoYXQgdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc3Vic2V0cyBvZiBkYXRhIGhhdmUgYmVlbiBjcmVhdGVkLCBtYWtlIHRpbWUgc2VyaWVzIG9iamVjdHMgZm9yIGVhY2gKClRTX1RyYWluMSA9IHRzKFRyYWluaW5nX0RhdGExJE5ZLCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMTAsIDkpKQpUU19UcmFpbjIgPSB0cyhUcmFpbmluZ19EYXRhMiROWSwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDEwLCAxMikpClRTX1RyYWluMyA9IHRzKFRyYWluaW5nX0RhdGEzJE5ZLCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMTEsIDQpKQpUU19UcmFpbjQgPSB0cyhUcmFpbmluZ19EYXRhNCROWSwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDEyLCAxKSkKCiMjIyBnb2luZyB0byB1c2UgdGhlIHN0bCgpIGZ1bmN0aW9uIHRvIGRlY29tcG9zZSBlYWNoIG9mIHRoZSB0cmFpbmluZyBkYXRhc2V0IHRpbWUgc2VyaWVzIG9iamVjdHMsIHRoZW4gdXNlIHRob3NlIGRlY29tcG9zZWQgb2JqZWN0cyBmb3IgZm9yZWNhc3RpbmcKClNUTF9UcmFpbmluZzEgPSBzdGwoVFNfVHJhaW4xLCBzLndpbmRvdyA9IDEyKQpTVExfVHJhaW5pbmcyID0gc3RsKFRTX1RyYWluMiwgcy53aW5kb3cgPSAxMikKU1RMX1RyYWluaW5nMyA9IHN0bChUU19UcmFpbjMsIHMud2luZG93ID0gMTIpClNUTF9UcmFpbmluZzQgPSBzdGwoVFNfVHJhaW40LCBzLndpbmRvdyA9IDEyKQoKIyMjIEZvcmVjYXN0IGNhbGN1bGF0aW9ucyB3aXRoIGRlY29tcG9zZWQgdHJhaW5pbmcgc2V0IHRpbWUgc2VyaWVzIG9iamVjdHMKCiAgIyBTZXQgaCA9IDEwIGFzIHRoZXJlIGlzIDEwIG9ic2VydmF0aW9ucyBpbiB0aGUgdGVzdGluZyBkYXRhc2V0LCBzbyB3ZSBjYW4gZG8gYSBvbmUtdG8tb25lIGNvbXBhcmlzb24gYmV0d2VlbiBvdXIgdHJhaW5pbmcgZm9yZWNhc3RzIGZvciBlYWNoIHRpbWUgc2VyaWVzIG1vZGVsIGFuZCBvdXIgb2JzZXJ2ZWQgdmFsdWVzIGluIHRoZSB0ZXN0aW5nIGRhdGFzZXQgKEFwcmlsIDIwMjQgdG8gSmFudWFyeSAyMDI1KQpUcmFpbl9TZXQxX0ZvcmVjYXN0cyA9IGZvcmVjYXN0KFNUTF9UcmFpbmluZzEsIGggPSAxMCwgbWV0aG9kID0gInJ3ZHJpZnQiKQpUcmFpbl9TZXQyX0ZvcmVjYXN0cyA9IGZvcmVjYXN0KFNUTF9UcmFpbmluZzIsIGggPSAxMCwgbWV0aG9kID0gInJ3ZHJpZnQiKQpUcmFpbl9TZXQzX0ZvcmVjYXN0cyA9IGZvcmVjYXN0KFNUTF9UcmFpbmluZzMsIGggPSAxMCwgbWV0aG9kID0gInJ3ZHJpZnQiKQpUcmFpbl9TZXQ0X0ZvcmVjYXN0cyA9IGZvcmVjYXN0KFNUTF9UcmFpbmluZzQsIGggPSAxMCwgbWV0aG9kID0gInJ3ZHJpZnQiKQpgYGAKCiMjIEV4YW1pbmluZyBlYWNoIFRyYWluaW5nIFNldCdzIEZvcmVjYXN0ZWQgVmFsdWVzCkJlbG93IEkgY3JlYXRlZCBib3RoIGEgdGFibGUgdG8gcXVhbnRpZnkgZWFjaCB0cmFpbmluZyBzZXQncyBmb3JlY2FzdHMgYXMgd2VsbCBhcyBhIGdyYXBoIHRvIHZpc3VhbGl6ZSB0aGVpciBwZXJmb3JtYW5jZXMgcmVsYXRpdmUgdG8gYm90aCBvbmUgYW5vdGhlciBhbmQgdGhlICoqdHJ1ZSoqIE5ldyBZb3JrIGhvbWUgdmFsdWVzIHByb3ZpZGVkIGluIHRoZSBvcmlnaW5hbCBkYXRhc2V0LiBBcyB3ZSBjYW4gc2VlLCBhbGwgb2YgdGhlIG1vZGVscyB1bmRlcmVzdGltYXRlZCB0aGUgcmlzZSBpbiBob21lIHZhbHVlcyB0aGF0IHdvdWxkIHRha2UgcGxhY2UgZnJvbSBBdWd1c3Qgb2YgMjAyNCB0byBKYW51YXJ5IG9mIDIwMjUuCmBgYHtyLCBmaWcuYWxpZ249J2NlbnRlcid9CiAgIyBVc2UgdGhlICRtZWFuIHNlbGVjdGlvbiB0byBzZWUgdGhlIGZvcmVjYXN0ZWQgcHJlZGljdGVkIHZhbHVlcyBhdCBwYXJ0aWN1bGFyIHBvaW50cwpUU01lYW4xID0gZGF0YS5mcmFtZShUcmFpbl9TZXQxX0ZvcmVjYXN0cyRtZWFuKQogIGNvbG5hbWVzKFRTTWVhbjEpID0gIkVycm9ycyIKVFNNZWFuMiA9IGRhdGEuZnJhbWUoVHJhaW5fU2V0Ml9Gb3JlY2FzdHMkbWVhbikKICBjb2xuYW1lcyhUU01lYW4yKSA9ICJFcnJvcnMiClRTTWVhbjMgPSBkYXRhLmZyYW1lKFRyYWluX1NldDNfRm9yZWNhc3RzJG1lYW4pCiAgY29sbmFtZXMoVFNNZWFuMykgPSAiRXJyb3JzIgpUU01lYW40ID0gZGF0YS5mcmFtZShUcmFpbl9TZXQ0X0ZvcmVjYXN0cyRtZWFuKQogIGNvbG5hbWVzKFRTTWVhbjQpID0gIkVycm9ycyIKWWVhcnMgPSBkYXRhLmZyYW1lKFRTX0RhdGEkRGF0ZVsxNzI6MTgxXSkKCkZvcmVjYXN0ZWRfVmFsdWVzID0gY2JpbmQoWWVhcnMsIFRTTWVhbjEsIFRTTWVhbjIsIFRTTWVhbjMsIFRTTWVhbjQsIFRlc3RpbmdfRGF0YVssMl0pCmNvbG5hbWVzKEZvcmVjYXN0ZWRfVmFsdWVzKSA9IGMoIkRhdGUiLCAiVFMgMSIsICJUUyAyIiwgIlRTIDMiLCAiVFMgNCIsICJUcnVlIFZhbHVlcyIpCmthYmxlKEZvcmVjYXN0ZWRfVmFsdWVzLCBjYXB0aW9uID0gIkZvcmVjYXN0ZWQgVmFsdWVzIFBlciBUcmFpbmluZyBTZXQiKQoKTGlzdF9PZl9EYXRlcyA9IGFzLkRhdGUoYygiMjAyNC0wNC0wMSIsICIyMDI0LTA1LTAxIiwgIjIwMjQtMDYtMDEiLCAiMjAyNC0wNy0wMSIsICIyMDI0LTA4LTAxIiwgIjIwMjQtMDktMDEiLCAiMjAyNC0xMC0wMSIsICIyMDI0LTExLTAxIiwgIjIwMjQtMTItMDEiLCAiMjAyNS0wMS0wMSIpKQoKVFMxID0gZGF0YS5mcmFtZShMaXN0X09mX0RhdGVzLCBhcy5kb3VibGUoVFNNZWFuMSRFcnJvcnMpKQpUUzIgPSBkYXRhLmZyYW1lKExpc3RfT2ZfRGF0ZXMsIGFzLmRvdWJsZShUU01lYW4yJEVycm9ycykpClRTMyA9IGRhdGEuZnJhbWUoTGlzdF9PZl9EYXRlcywgYXMuZG91YmxlKFRTTWVhbjMkRXJyb3JzKSkKVFM0ID0gZGF0YS5mcmFtZShMaXN0X09mX0RhdGVzLCBhcy5kb3VibGUoVFNNZWFuNCRFcnJvcnMpKQoKcGxvdChUZXN0aW5nX0RhdGEsIGNvbCA9ICJibHVlIiwgbHdkID0gMiwKICAgICBtYWluID0gIkZvcmVjYXN0ZWQgVnMgVHJ1ZSBOZXcgWW9yayBIb21lIFZhbHVlcyBcbiAoQXVndXN0IDIwMjQgLSBKYW51YXJ5IDIwMjUpIiwKICAgICB4bGFiID0gIkRhdGUiLAogICAgIHlsYWIgPSAiVmFsdWUoJFVTRCkiKQogIGxpbmVzKFRlc3RpbmdfRGF0YSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQogIGxpbmVzKFRTMSwgY29sID0gInJlZCIsIGx3ZCA9IDIpCiAgICBwb2ludHMoVFMxLCBjb2wgPSAicmVkIikKICBsaW5lcyhUUzIsIGNvbCA9ICJibGFjayIsIGx3ZCA9IDIpCiAgICBwb2ludHMoVFMyLCBjb2wgPSAiYmxhY2siKQogIGxpbmVzKFRTMywgY29sID0gImdyZWVuIiwgbHdkID0gMikKICAgIHBvaW50cyhUUzMsIGNvbCA9ICJncmVlbiIpCiAgbGluZXMoVFM0LCBjb2wgPSAicHVycGxlIiwgbHdkID0gMikKICAgIHBvaW50cyhUUzQsIGNvbCA9ICJwdXJwbGUiKQogICAgbGVnZW5kKCJ0b3BsZWZ0IiwKICAgICAgIGxlZ2VuZCA9IGMoIlRydWUgVmFsdWVzIiwgIlRpbWUgU2VyaWVzIDEiLCAiVGltZSBTZXJpZXMgMiIsCiAgICAgICAgICAgICAgICAgICJUaW1lIFNlcmllcyAzIiwgIlRpbWUgU2VyaWVzIDQiKSwKICAgICAgIGNvbCA9IGMoImJsdWUiLCAicmVkIiwgImJsYWNrIiwgImdyZWVuIiwgInB1cnBsZSIpLAogICAgICAgbHR5ID0gMSwgcGNoID0gMTYsIGx3ZCA9IDIpCmBgYAoKIyMgVHJhaW5pbmcgU2V0IEZvcmVjYXN0IEVycm9yIEFuYWx5c2lzCkFzIHdlIHNhdyBhYm92ZSwgdGhlcmUgd2FzIGEgY29uc2lzdGVudCB1bmRlcmVzdGltYXRpb24gYnkgZWFjaCBvZiB0aGUgdHJhaW5pbmcgc2V0IHRpbWUgc2VyaWVzLiBIb3dldmVyLCB0aGVyZSBhcHBlYXJlZCB0byBiZSBhIGxpbmVhciBhbmQgbmVnYXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc2FtcGxlIHNpemUgb2YgdGhlIHRyYWluaW5nIHNldCwgYW5kIHRoYXQgc2V0J3MgZm9yZWNhc3RzIHJlbGF0aXZlIHRvIHRoZSB0cnVlIHZhbHVlcy4gVHJhaW5pbmcgc2V0IDQgaGFkIHRoZSBzbWFsbGVzdCBzYW1wbGUgc2l6ZSAoYmVnaW5uaW5nIGF0IEphbnVhcnkgb2YgMjAxMikgYW5kIHdhcyB0aGUgbW9zdCBhY2N1cmF0ZS4KCkEgbnVtZXJpYyBicmVha2Rvd24gb2YgZWFjaCB0cmFpbmluZyBzZXRzIGZvcmVjYXN0cycgYWNjdXJhY3kgaXMgYmVsb3cuIFRoZSBtZXRyaWNzIEkgdXNlZCB3ZXJlIG1lYW4gZXJyb3IgKE1FKSwgbWVhbiBzcXVhcmUgZXJyb3IgKE1TRSkgYW5kIG1lYW4gYWJzb2x1dGUgcHJlZGljdGlvbiBlcnJvciAoTUFQRSkuIEFzIHNlZW4gaW4gdGhlIHZpc3VhbHMgYWJvdmUsIGFzIHRoZSBzYW1wbGUgc2l6ZSBvZiBvdXIgdGltZSBzZXJpZXMgdHJhaW5pbmcgc2V0IGRlY3JlYXNlZCwgaXRzIGFjY3VyYWN5IGluY3JlYXNlZC4gCgpUaGlzIGlzIGxpa2VseSBkdWUgdG8gbm9uLWxpbmVhciByaXNlIGluIE5ldyBZb3JrIGhvbWUgdmFsdWVzLCBlc3BlY2lhbGx5IGZyb20gMjAxOCB0byAyMDI1LiBUaGUgc21hbGxlciB0aW1lIHNlcmllcyB0cmFpbmluZyBzZXRzIHdlcmUgbGVzcyBpbmZsdWVuY2VkIGJ5IHRoZSBsZXNzZXIgaG9tZSB2YWx1ZXMgb2YgdGhlIGVhcmx5IHBhcnRzIG9mIHRoZSAyMDEwcy4KYGBge3IsIEVycm9yIEFuYWx5c2lzfQojIyMjIyMjIERlZmluZSBFcnJvciBPYmplY3RzClRTX0ZvcmVjYXN0czFfRXJyb3JzID0gVGVzdGluZ19EYXRhWywyXSAtIFRTTWVhbjEKVFNfRm9yZWNhc3RzMl9FcnJvcnMgPSBUZXN0aW5nX0RhdGFbLDJdIC0gVFNNZWFuMgpUU19Gb3JlY2FzdHMzX0Vycm9ycyA9IFRlc3RpbmdfRGF0YVssMl0gLSBUU01lYW4zClRTX0ZvcmVjYXN0czRfRXJyb3JzID0gVGVzdGluZ19EYXRhWywyXSAtIFRTTWVhbjQKCiMjIyMjIyMgTUUKVFMxX01FID0gc3VtKFRTX0ZvcmVjYXN0czFfRXJyb3JzKS9ucm93KFRTX0ZvcmVjYXN0czFfRXJyb3JzKQpUUzJfTUUgPSBzdW0oVFNfRm9yZWNhc3RzMl9FcnJvcnMpL25yb3coVFNfRm9yZWNhc3RzMl9FcnJvcnMpClRTM19NRSA9IHN1bShUU19Gb3JlY2FzdHMzX0Vycm9ycykvbnJvdyhUU19Gb3JlY2FzdHMzX0Vycm9ycykKVFM0X01FID0gc3VtKFRTX0ZvcmVjYXN0czRfRXJyb3JzKS9ucm93KFRTX0ZvcmVjYXN0czRfRXJyb3JzKQoKIyMjIyMjIyBNU0UKVFMxX01TRSA9IHN1bShUU19Gb3JlY2FzdHMxX0Vycm9yc14yKS9ucm93KFRTX0ZvcmVjYXN0czFfRXJyb3JzKQpUUzJfTVNFID0gc3VtKFRTX0ZvcmVjYXN0czJfRXJyb3JzXjIpL25yb3coVFNfRm9yZWNhc3RzMl9FcnJvcnMpClRTM19NU0UgPSBzdW0oVFNfRm9yZWNhc3RzM19FcnJvcnNeMikvbnJvdyhUU19Gb3JlY2FzdHMzX0Vycm9ycykKVFM0X01TRSA9IHN1bShUU19Gb3JlY2FzdHM0X0Vycm9yc14yKS9ucm93KFRTX0ZvcmVjYXN0czRfRXJyb3JzKQoKIyMjIyMjIyBNQVBFClRTMV9NQVBFID0gKHN1bShhYnMoKFRTX0ZvcmVjYXN0czFfRXJyb3JzL1Rlc3RpbmdfRGF0YVssMl0pKjEwMCkpKS9ucm93KFRTX0ZvcmVjYXN0czFfRXJyb3JzKQpUUzJfTUFQRSA9IChzdW0oYWJzKChUU19Gb3JlY2FzdHMyX0Vycm9ycy9UZXN0aW5nX0RhdGFbLDJdKSoxMDApKSkvbnJvdyhUU19Gb3JlY2FzdHMyX0Vycm9ycykKVFMzX01BUEUgPSAoc3VtKGFicygoVFNfRm9yZWNhc3RzM19FcnJvcnMvVGVzdGluZ19EYXRhWywyXSkqMTAwKSkpL25yb3coVFNfRm9yZWNhc3RzM19FcnJvcnMpClRTNF9NQVBFID0gKHN1bShhYnMoKFRTX0ZvcmVjYXN0czRfRXJyb3JzL1Rlc3RpbmdfRGF0YVssMl0pKjEwMCkpKS9ucm93KFRTX0ZvcmVjYXN0czRfRXJyb3JzKQoKIyMjIyMgVGFibGUgdG8gVmlzdWFsaXplCkFsbF9NRXMgPSByYmluZChUUzFfTUUsIFRTMl9NRSwgVFMzX01FLCBUUzRfTUUpCkFsbF9NU0VzID0gcmJpbmQoVFMxX01TRSwgVFMyX01TRSwgVFMzX01TRSwgVFM0X01TRSkKQWxsX01BUEVzID0gcmJpbmQoVFMxX01BUEUsIFRTMl9NQVBFLCBUUzNfTUFQRSwgVFM0X01BUEUpCgpGb3JlY2FzdF9FcnJvcnMgPSBjYmluZChBbGxfTUVzLCBBbGxfTVNFcywgQWxsX01BUEVzKQpjb2xuYW1lcyhGb3JlY2FzdF9FcnJvcnMpID0gYygiTUUiLCAiTVNFIiwgIk1BUEUiKQpyb3duYW1lcyhGb3JlY2FzdF9FcnJvcnMpID0gYygiVFMxIiwgIlRTMiIsICJUUzMiLCAiVFM0IikKa2FibGUoRm9yZWNhc3RfRXJyb3JzLCBjYXB0aW9uID0gIk1vZGVsIEZvcmVjYXN0cycgQWNjdXJhY3kgTWVhc3VyZXMiKQpgYGAKCiMgQ29uY2x1c2lvbgpVbHRpbWF0ZWx5LCB3aGVuIGxvb2tpbmcgYXQgTmV3IFlvcmsgc3RhdGUncyBob21lIHZhbHVlcyBvdmVyIHRoZSBwYXN0IDE1IHllYXJzLCBmb3JlY2FzdGluZyBtb250aGx5IGluZGV4IHZhbHVlcyB2aWEgU1RMLWRlY29tcG9zZWQgdHJhaW5pbmcgc2V0cyBkaWQgbm90IHlpZWxkIHBhcnRpY3VsYXJseSBhY2N1cmF0ZSByZXN1bHRzLiBEZXNwaXRlIHRyYWluaW5nIG91ciBmb3JlY2FzdCBhbGdvcml0aG0gd2l0aCB0aGUgZHJpZnQgbWV0aG9kLCB3aGljaCBpcyBtZWFudCB0byB0YWtlIGludG8gYWNjb3VudCBoaXN0b3JpY2FsIGluY3JlYXNlcyBhbmQgZGVjcmVhc2VzLCBhbGwgZm91ciBvZiBvdXIgdGltZSBzZXJpZXMgdW5kZXJlc3RpbWF0ZWQgdGhlIHRydWUgdmFsdWVzIG9mIE5ldyBZb3JrJ3MgaG9tZSB2YWx1ZSBpbmRleCBmcm9tIEF1Z3VzdCBvZiAyMDI0IHRvIEphbnVhcnkgb2YgMjAyNS4KCkluIGEgZnV0dXJlIGFuYWx5c2lzLCBpdCB3b3VsZCBwb3NzaWJseSBiZSB2YWx1YWJsZSBkdXJpbmcgdGhlIHRyYWluaW5nIHNldCBwcm9jZXNzLCB0byB3aWRlbiB0aGUgc2NvcGUgb2Ygc2FtcGxlIHNpemUgc2VsZWN0aW9uLiBEb2luZyBzbyB3b3VsZCBhbGxvdyB1cyB0byBzZWUgYXQgd2hpY2ggcG9pbnQgZG9lcyBjb25zdHJhaW5pbmcgdGhlIHRpbWUgaW50ZXJ2YWwgb2Ygb2JzZXJ2YXRpb25zIGZvciB0aGUgdHJhaW5pbmcgZGF0YSBiZWNvbWUgZGV0cmltZW50YWwuIEFzIGluIHRoaXMgaW5zdGFuY2UsIHdpdGggdGhlIG1heGltdW0gbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBjb21pbmcgb3V0IGJlaW5nIHNldCB0byAzMCwgd2Ugc2F3IGEgZGlyZWN0bHkgbmVnYXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gc2FtcGxlIHNpemUgb2YgdGhlIHRyYWluaW5nIHNldCBhbmQgZm9yZWNhc3RzJyBhY2N1cmFjeS4KCiMgUmVmZXJlbmNlcwpPcmlnaW5hbCBEYXRhc2V0IFNvdXJjZToKCi0gaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9yb2Jpa3NjdWJlL3ppbGxvdy1ob21lLXZhbHVlLWluZGV4CgpEYXRhc2V0IERvd25sb2FkIExpbmsgdmlhIEdpdGh1YjoKCi0gaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NocmlzQjIzMjMvU1RBMzIxL3JlZnMvaGVhZHMvbWFpbi9aaWxsb3dfRGF0YS5jc3Y=