Abstract

When the tectonic plate boundaries were first recognised, they were identified by several factors, one of which included patterns observed from seismic activity data. The data inherently marks regions of seismic activity where the tectonic forces converge and it is widely known that seismic events are associated with all tectonic plate boundaries. In this study, I will explore the complex relationship between the seismic energy and its plate proximity. Making use of a seismic event dataset from the year of 2023 and a dataset containing geographic coordinates that completely enclose all tectonic plate boundaries, I investigate how seismic magnitude relates to the proximity of a plate boundary. By examining over 26,000 recorded seismic events with the use of various data preprocessing methods I begin to understand the behavior of our data, assemble several visualizations to observe the behavior and identify patterns and relationships. With those relationships I will compare different predictive analysis methods and uncover the detailed dynamics those relationships hold. With the use of the decision tree-based model Random Forest, the results indicate the seismic magnitude that can be identified with the plate proximity using the extreme value theorem. It provides initial insight into understanding the relationship between the seismic magnitude level and its plate proximity.

Introduction

Being born and raised in Iceland, “the land of fire and ice”, I have been exposed to multiple seismic activities, which sparked interest in the science of seismology. Iceland is located in between two tectonic plates, the Eurasian plate and the North American Plate and experiences frequent seismic activity due to its tectonic setting. When the plate boundaries were first discovered and drawn on a map, scientists drew the boundaries along areas of high seismicity, so it is widely known that seismic activity is highly correlated with the tectonic plates (Wilson, 2021). There are three different types of plate boundaries. A “convergent” plate boundary, where the crusts come together and collide. In some cases, an event called “subduction” occurs where one tectonic plate dives underneath the other. The second type is a “divergent” plate boundary. Where the two tectonic plates spread apart and often can form a ridge. The third type is a “transform” plate boundary. The two crusts slide past one another, horizontally (National Geographic Society, 2024).

In November of 2023, the town of Grindavík near the Reykjanes Peninsula of Iceland encountered numerous seismic events. During the week of November 7th to 14th, approximately 13,700 seismic events were recorded with over 1,000 being significant. This significant seismic activity is what inspired my interest in exploring this topic further. Figure 1 Highlights the extent that the damage occurred and shows the fissure that had emerged through the town. The town has remained evacuated since (“Vikuleg Jarðskjálftayfirlit” n.d.).

Figure 1: Fissure caused by seismic activity in the town of Grindavík, Iceland in November 2023. The damage illustrates the severness of seismic events in the town Seismology became its own science in the late nineteenth century and since then there has been a lot of research about the relationship between the depths of seismic events and plate boundaries (Agnew, 1989). Most events occur on plate boundaries but it is dependent on the type, how deep the event goes. For example, according to Wilson (2021), “Transform boundaries tend to have steeper rupture surfaces, which cause the earthquakes to occur in a narrow zone and limits their size”. As mentioned earlier, subduction occurs when one crust goes beneath another. Its seismic activity is very abundant and causes greater depth in the crust than in other plate boundaries (Wilson, 2021). There is also a correlation between the intensity of the seismic event and its depth. With a deeper event, the distance from the source to the surface of the crust increases and the strength of shaking diminishes. Consequently, two events with equal strength but varying depths carry different levels of magnitude (“At what depth do earthquakes occur? What is the significance of the depth?”, n.d).

While it has been established that the majority of seismic events lie between the plate boundaries, there remains a subset of events that occur far away from these boundaries. Shallow events can yield to a greater impact however, the question remains: do seismic events that occur further away from plate boundaries also exhibit high magnitudes? In this study, I delve into seismic event dataset from the year of 2023 to understand the correlation between seismic magnitude and their proximity to plate boundaries.

Methods

Data Preprocessing

I acquired a dataset documenting global seismic events throughout the year 2024 from Kaggle.com. The dataset includes over 22 attributes, providing information on more than 26,000 recorded seismic events. Key attributes include magnitude, time, depth and geographic coordinates of each event. However, as the dataset lacked information about tectonic plates, I obtained an additional dataset containing the geographic coordinates of all tectonic plates, major and minor, along with their respective names (Keser, 2023; Thompson, 2020). An illustration of the earth’s lithosphere with the marking of all plate boundaries is shown in figure 2.

Figure 2: Map illustrating all major and minor tectonic plate boundaries.
Figure 2: Map illustrating all major and minor tectonic plate boundaries.

The majority of the data preprocessing methods were used using python; details of the code can be found in the appendix. Initially, the dataset contained over 26,000 entries. However, to ensure the accuracy of the data, entries with missing values were removed resulting in approximately 22,000 valid observations.

To investigate the proximity of seismic events to tectonic plates, a new attribute named “distance” was created, calculated using the Haversine Formula. This mathematical formula is used to calculate the shortest distance between two points on the surface of a sphere in kilometers:

\[ a = \sin^2\left(\frac{\Delta lat}{2}\right) + \cos(lat_1) \cdot \cos(lat_2) \cdot \sin^2\left(\frac{\Delta lon}{2}\right) \]

\[ c = 2 \cdot \text{atan2}\left(\sqrt{a}, \sqrt{1-a}\right) \]

\[ d = R \cdot c \]

Where \(d\) is the distance between the two points (along the surface of the sphere), \(\Delta lat\) is the difference in latitude between the two points, \(\Delta lon\) is the difference in longitude between the two points, \(R\) is the radius of the sphere (6,371 kilometers), \(lat_1\) and \(lon_2\) are the latitudes of the two points in radians, \(\text{atan2}\) is the two-argument arctangent function (Upadhyay, 2024).

The rest of the preprocessing steps were performed in RStudio. These steps involve removing unnecessary attributes and adjusting data types to simplify further research. The table below outlines the attributes of the data that will be utilized in this study.

# Removing unnecessary columns (id & updated)
Earthquakes <- earthquake_plates_df[, c("time", "latitude", "longitude", "depth", "mag", "type", "area", "distance", "plate_latitude", "plate_longitude", "plate_name")]

# Making a dataframe with only earthquakes (26,428)
  # only including magnitude of 4.5 and above
df = Earthquakes %>%
  filter(type == "earthquake") %>% 
  filter(mag > 4.499)

# Converting column types
df$time <- as.POSIXct(df$time, format="%Y-%m-%dT%H:%M:%OSZ", tz = "UTC")
df$mag = as.numeric(df$mag)
df$type = as.factor(df$type)

Exploratory Data Analysis

Before diving into complex analysis, I conducted Exploratory Data Analysis (EDA) to understand the structure and distribution of the dataset. EDA serves as a crucial step in understanding the underlying patterns and relationship with the data.

  • It is recommended to scroll down to the bottom of the sheet and click the button that says Change display settings and choose desktop layout. Then you should see the visualizations as desired.

Magitude Distribution

The distribution of seismic magnitudes is represented in figure Magnitude Distribution through an area plot. Upon examination I observed an irregular and inconsistent pattern up to the value of 4.5. This observation led me to believe that the reliability of these data points were questionable. Consequently, all data points below a magnitude of 4.5 have been excluded from the dataset. The analysis will focus more on significant seismic events, ensuring more robust research. Left are approximately 8,600 observations.

The table below outlines the summary statistics of the key attributes. As previously mentioned, the minimum magnitude recorded is 4.5. Interestingly, both the mean and the median values are similar to the minimum value. Similarly, for the depth and the distance, their mean and median values align closely to the minimum value. These summaries indicate that a large portion of the data points are clustered closely to the minimum values.

##      depth              mag          distance        
##  Min.   :  1.873   Min.   :4.50   Min.   :   0.3696  
##  1st Qu.: 10.000   1st Qu.:4.50   1st Qu.:  32.9213  
##  Median : 16.000   Median :4.60   Median :  62.8752  
##  Mean   : 64.055   Mean   :4.75   Mean   : 119.1783  
##  3rd Qu.: 61.881   3rd Qu.:4.90   3rd Qu.: 131.5074  
##  Max.   :653.516   Max.   :7.80   Max.   :2310.7683

Depth Distribution Map

Visualizations play an important role in EDA, allowing us to identify trends, outliers and potential relationships in our attributes. Figure Depth Distribution Map displays the seismic events distributed on a map with each point representing an event. The size and color indicate the depth, highlighting the deep events in southeast Asia. This region corresponds to the convergence of the Eurasian and the North American plates, forming a convergent plate boundary, prone to subduction. As previously mentioned, subduction often results in greater depths compared to other plates. This visualization thereby supports that observation.

Frequency of Earthquakes

Figure Frequency of Earthquakes, showcases a dashboard featuring multiple visualizations that will increase our understanding of the data. Figure a, exhibits the same area plot shown in figure 3, though with the data points less than 4.5 excluded. Over 3,000 recorded observations register a magnitude of 4.5, representing 41% of our data and demonstrating a right skewness in the distribution. As the magnitude increases, the frequency sharply declines, supporting our earlier statement that a significant portion of the data is clustered closely around the minimum values.

Figure b, illustrates a density map representing the activity around the globe. Meanwhile, figure c illustrates a time series plot showcasing the distribution of the seismic activity throughout the year 2023. The time series plot displays a generally uniform distribution, marked by three noticeable spikes in activity. The tallest spike occurs on December 2nd and 3rd, recording over 350 seismic events solely in the Philippines. The heightened activity is noticeable on the map, particularly in Southeast Asia.

Distance by Area

Displayed in figure Distance by Area and Plate Proximity and Magnitude, are detailed information about the “distance” attribute in hope to have a better understanding of its distributions and relationships. The regions furthest away from the plate boundaries are showcased in a barplot in figure Distance by Area, with each bar labeled with the count of events occurring within that region. The map shows the seismic events with the sizes corresponding to the distance. The seismic event that occurred furthest away from a plate is located in the French Polynesia Region which is located on the Pacific Plate.

Plate Proximity and Magnitude

Illustrated in figure a, the bar plot represents the distribution of the distance in sets of 100 kilometers. The first bar represents over 5,000 data points which is approximately 65% of our total data points. As previously discussed, the majority of seismic activity lies between or close to plate boundaries so this information should not come as a surprise. As the distance increases, the frequency dramatically decreases. From a closer look, up to 20 observations are more than 1,500 kilometers from the nearest tectonic plate.

Figure b, a key visualization, showcases the correlation between the seismic magnitude and plate proximity, also known as the distance. Initially the plot suggests a negative linear relationship between the two attributes, indicating that as the distance from the event increases the magnitude decreases. However, upon closer inspection, it becomes evident that the majority of the data points cluster within the range of 4.5 to 5.0 magnitude and 0 to 100 kilometers in distance. Consequently, implementing a simple linear regression leads to insignificant results. Nonetheless, as initially suggested, the highest values for each magnitude set, in increments of 0.1, show a negative linear relationship. With this observation in mind, I turned to the Extreme Value Theorem, which provides a mathematical framework to deal with extreme events and their probabilities. Additionally, an extra attribute has been included in the dataset that aggregates the maximum distance for each set of magnitude, in increments of 0.1.

# Create a column magFactor, increments of 0.1
breaks <- seq(4.5, 8.0, by = 0.1)
labels <- paste0(breaks[1:length(breaks)-1])
df$magFactor <- cut(df$mag, breaks = breaks, labels = labels, right = FALSE)

# using extreme value theorem
# Aggregating highest minPlateDistance for each magFactor level
max_distance <- df %>%
  group_by(magFactor) %>%
  summarise(max_distance = max(distance))

# Merging aggregated data back into original dataframe
df <- left_join(df, max_distance, by = "magFactor")

The plot below, showcases the relationship between the maximum distance and the seismic magnitude.

ggplot(df, aes(x = magFactor, y = max_distance)) +
  geom_point(color = "#f0a0d1", size = 3, alpha = 0.6) + 
  labs(x = "Magnitude", y = "Maximum Distance") +
  ggtitle("Maximum distance by Sets of Magnitude") +
  theme_ipsum() + 
  theme(
    plot.title = element_text(size = 14, face = "bold"), 
    axis.title = element_text(size = 12), 
    axis.text = element_text(size = 10), 
    legend.position = "none"
  )

Frequency by Country

The figure Frequency by Country illustrates the frequency of seismic events for each country.

Modeling

To answer the research question of whether seismic events occurring further from plate boundaries also exhibit high magnitudes, I conducted and compared various data modeling methods. To ensure an unbiased evaluation of the models performance, the dataset was divided into a training set and a testing set. The training set contains 80% of the original data and the testing contains the remaining 20%. I explored four distinct modeling techniques using cross-validation to analyze the relationship between seismic magnitude and maximum distance from plate boundary. The corresponding code can be found in the appendix.

  1. Random Forest: Random Forest is an ensemble tree-based method that constructs multiple decision trees and outputs the mean prediction of the individual trees (James, Witten, Hastie, & Tibshirani, 2023).

  2. Gradient Boosting Machine (GBM): GBM is a boosting algorithm that is also a tree-based method. It builds multiple decision trees with each tree trying to correct the error from the previous one (James, Witten, Hastie, & Tibshirani, 2023).

  3. Recursive Partitioning Tree (RPT): RPT is also a tree-based method. It is a non-linear predictive model that divides the dataset into subsets based on the values of the input variables (Izenman, 2013).

  4. Linear Regression: A supervised learning model that is used to model the relationship between a dependent variable and an independent variable (James, Witten, Hastie, & Tibshirani, 2023).

For all modeling techniques, the magnitude was the dependent variable and the maximum distance was the independent variable and they were trained on the training set.

# Splitting the data into training and testing
library(caret)
set.seed(123)
train_index <- createDataPartition(df$mag, p = 0.8, list = FALSE, times = 1)
train_data <- df[train_index, ]
test_data <- df[-train_index, ]

# Training set with a repeated cross validation
train_ctrl <- trainControl(method = "repeatedcv", 
                           number = 5, 
                           repeats = 3)

set.seed(2018)

# Recursive Partitioning Tree with only distance as an attribute
rpart_tree_dist <- train(mag ~ max_distance,
                    data = train_data,
                    method = "rpart",
                    trControl = train_ctrl)

# Random Forest Tree with only Distance as an attribute
rf_tree_dist <- train(mag ~ max_distance,
                 data = train_data,
                 method = "rf",
                 trControl = train_ctrl)

# Gradient Boosting Machine with only distance as an attribute
gbm_tree_dist <- train(mag ~ max_distance,
                  data = train_data,
                  method = "gbm",
                  trControl = train_ctrl,
                  distribution = "gaussian",
                  verbose = FALSE)

lm_tree_dist <- train(mag ~ max_distance,
                  data = train_data,
                  method = "lm",
                  trControl = train_ctrl)

resamp <- resamples(list(
  rpart_tree = rpart_tree_dist, 
  randomForest = rf_tree_dist,
  GBM = gbm_tree_dist,
  LM = lm_tree_dist
))

summary(resamp)
## 
## Call:
## summary.resamples(object = resamp)
## 
## Models: rpart_tree, randomForest, GBM, LM 
## Number of resamples: 15 
## 
## MAE 
##                      Min.      1st Qu.       Median         Mean      3rd Qu.
## rpart_tree   7.176971e-02 0.0758110983 0.1198031832 0.1050652260 0.1211041488
## randomForest 8.407123e-05 0.0002678523 0.0003931967 0.0004231218 0.0005226849
## GBM          1.012660e-02 0.0109467341 0.0112146544 0.0115517620 0.0119968390
## LM           1.021051e-01 0.1046228429 0.1060864451 0.1059956579 0.1071815893
##                     Max. NA's
## rpart_tree   0.123251011    0
## randomForest 0.001016477    0
## GBM          0.014317666    0
## LM           0.109145949    0
## 
## RMSE 
##                     Min.     1st Qu.      Median        Mean    3rd Qu.
## rpart_tree   0.127610564 0.149824866 0.158225602 0.154570756 0.16078231
## randomForest 0.002156425 0.004940049 0.006588671 0.007186277 0.00907489
## GBM          0.022446949 0.027401862 0.038809647 0.040641444 0.04559480
## LM           0.153469966 0.161230648 0.166517459 0.165061147 0.16823104
##                    Max. NA's
## rpart_tree   0.16967287    0
## randomForest 0.01510011    0
## GBM          0.06854230    0
## LM           0.17664487    0
## 
## Rsquared 
##                   Min.   1st Qu.    Median      Mean   3rd Qu.      Max. NA's
## rpart_tree   0.7872643 0.8002255 0.8126187 0.8225648 0.8508787 0.8779127    0
## randomForest 0.9984821 0.9994471 0.9996908 0.9995625 0.9998317 0.9999598    0
## GBM          0.9684938 0.9848159 0.9878878 0.9869058 0.9945208 0.9961752    0
## LM           0.7871931 0.7930239 0.7968752 0.7987650 0.8043737 0.8116570    0

Results

The visualization below illustrates the results from the four trained models that were mentioned in the modeling section. The figure shows the box plots of three different values. The first box plot represents the Mean Absolute Error (MAE) of the models. The MAE measures the absolute average difference between the predictive value and the actual value. A lower MAE indicates a better model. The second box plot represents the Root Mean Squared Error (RMSE). The RMSE measures the square root average difference between the predictive value and the actual value. It is very similar to MAE, with a lower value indicating a better model; however, the RMSE is more sensitive to larger errors and tends to be more accurate. The third box plot represents the \(R^2\) values. The \(R^2\) measures how well the independent variable can explain the dependent variable. The value ranges from 0 to 1 where the closer the value is to 1, the better the independent variable can explain the dependent variable.

# Extract values from resamp object
resamp_values <- resamp$values

# Reshape the data to long format
resamp_long <- pivot_longer(resamp_values, cols = -Resample, names_to = "Model_Metric", values_to = "Value")

# Extract models and metrics from the Model_Metric column
resamp_long <- separate(resamp_long, col = Model_Metric, into = c("Model", "Metric"), sep = "~")

resamp_long$Model <- factor(resamp_long$Model, 
                            levels = c("randomForest", "rpart_tree", "GBM", "LM"),
                            labels = c("Random Forest", "RPT", "GBM", "Linear Regression"))

custom_palette <- c("#0072B2", "#D55E00", "#009E73", "#CC79A7")

# Creating a theme
custom_theme <- theme_ipsum(base_size = 12) +
  theme(
    panel.grid.major.y = element_line(color = "grey80"),
    panel.grid.minor.y = element_blank(),
    axis.text.x = element_text(angle = 45, hjust = 1) 
  )

ggplot(data = resamp_long, aes(x = Model, y = Value, fill = Model)) +
  geom_boxplot(outlier.shape = NA, width = 0.6) +
  facet_wrap(~ Metric, scales = "free_y") +
  scale_fill_manual(values = custom_palette) +
  labs(title = "Boxplot of Metrics by Model",
       x = "Model",
       y = "Value",
       fill = "Model") +
  custom_theme

As previously discussed, lower MAE and RMSE values, along with a high value of the R2 indicates a better model performance. Therefore, the objective is to identify the model that shows the best results. Upon initial inspection, the Random Forest model outperformed the other models across all scales. The MAE and RMSE values suggest that the predictions were generally accurate with little to none variation. The \(R^2\) value of 0.9996 shows that the model explained the majority of the variance in the data. Overall, these results indicate that the model captured patterns in the data and it is highly accurate and reliable.

# Making predictions using randomForest model
predictions_rf <- predict(rf_tree_dist, newdata = test_data)

cat("Random Forest Prediction:", mean(predictions_rf), "\n")
## Random Forest Prediction: 4.755023

The trained random forest model was used to make predictions on the testing dataset, resulting in a predicted seismic magnitude of 4.755. This prediction explains the model’s ability to estimate the magnitude based on the maximum plate proximity. Notably, the mean of the magnitude in the dataset is 4.75 which indicates that the predicted value aligns closely with the average magnitude observed in the dataset.

Conclusion

The science of seismology is dated back to the late nineteenth century and scientists have found valuable insights in the correlation between seismic activity and plate tectonics. Over the years, they have linked the depth of a seismic event with the seismic magnitude. As well as the different effects and characteristics between boundary types. In this study, I investigated the impact of plate proximity on seismic magnitude using a dataset of approximately 8,600 recorded seismic events from the year 2023. With the help of the Haversine formula, I created an additional attribute representing the distance between each seismic event and the nearest tectonic plate.

By combining various visualizations, I understood the behavior and relationship between seismic magnitude and plate proximity. By implementing the Extreme value theorem, I uncovered a pattern indicating a greater plate proximity has correlation with lower seismic magnitude within the dataset. Utilizing this pattern, I trained a Random Forest model to predict the magnitude of a seismic event with the maximum distance from a tectonic plate. Finally, I used the trained model to make predictions on the untrained part of the dataset, with accurate and reliable results.

References

Agnew D. C. (1989, January 1). Seismology History. Springer Link. https://link.springer.com/referenceworkentry/10.1007/0-387-30752-4_143

At what depth do earthquakes occur? What is the significance of the depth?. (n.d.). USGS. Retrieved April 27, 2024, from https://www.usgs.gov/faqs/what-depth-do-earthquakes-occur-what-significance-depth

Izenman, A.J. (2013). Recursive Partitioning and Tree-Based Methods. In: Modern Multivariate Statistical Techniques. Springer Texts in Statistics. Springer, New York, NY. https://doi.org/10.1007/978-0-387-78189-1_9

James, G., Witten, D., Hastie, T. & Tibshirani, R. (2023). An Introduction to Statistical Learning: with Applications in R: Second Edition.

Keser, M. (2023, December 30). Earthquakes 2023 Global. Kaggle. Retrieved January 30, 2024, from https://www.kaggle.com/datasets/mustafakeser4/earthquakes-2023-global

National Geographic Society. (2024, March 7). Plate Boundaries. National Geographic. https://education.nationalgeographic.org/resource/plate-boundaries/

Thompson, C. (2020, May 13). Tectonic Plate Boundaries. Kaggle. Retrieved March 26, 2024, from https://www.kaggle.com/datasets/cwthompson/tectonic-plate-boundaries/data

Upadhyay, A. (2024, January 21). Haversine formula - Calculate geographic distance on earth. Igismap. https://www.igismap.com/haversine-formula-calculate-geographic-distance-earth/

Vikuleg Jarðskjálftayfirlit. (n.d.). Veðurstofa Íslands. Retrieved April 27, 2024, from https://www.vedur.is/skjalftar-og-eldgos/yfirlit/manudir/jardskjalftayfirlit-45-viku-07-14-november-2023

Wilson, M. (2021, June 7). 5.3 Earthquakes and Plate Tectonics. Maricopa. https://open.maricopa.edu/hazards/chapter/earthquakes-and-plate-tectonics/

LS0tCnRpdGxlOiAiVGhlIEludGVycGxheSBvZiBNYWduaXR1ZGUgYW5kIFBsYXRlIFByb3hpbWl0eTogVGhlIHN0dWR5IG9mIDIwMjMgZ2xvYmFsIGVhcnRocXVha2UgdHJlbmRzIgphdXRob3I6IEJyeW5oaWxkdXIgVHJhdXN0YWTDs3R0aXIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IGpvdXJuYWwKICAgIGhpZ2hsaWdodDogemVuYnVybgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwotLS0KIApgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UpCmxpYnJhcnkodGlkeXZlcnNlKSAgIyBEYXRhIG1hbmlwdWxhdGlvbiBhbmQgdmlzdWFsaXphdGlvbgpsaWJyYXJ5KGRwbHlyKSAgICAgICMgbW9kaWZpZXMgZGF0YWZyYW1lcwpsaWJyYXJ5KGNhcmV0KSAgICAgICMgTWFjaGluZSBsZWFybmluZyBtb2RlbCB0cmFpbmluZyBhbmQgZXZhbHVhdGlvbgpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkgICMgUmFuZG9tIEZvcmVzdCBtb2RlbCB0cmFpbmluZwpsaWJyYXJ5KGdibSkgICAgICAgICMgR3JhZGllbnQgQm9vc3RpbmcgTWFjaGluZSAoR0JNKSBtb2RlbCB0cmFpbmluZwpsaWJyYXJ5KHJwYXJ0KSAgICAgICMgUmVjdXJzaXZlIFBhcnRpdGlvbmluZyBUcmVlcyBtb2RlbCB0cmFpbmluZwpsaWJyYXJ5KGNvcnJwbG90KSAgICMgQ29ycmVsYXRpb24gcGxvdCB2aXN1YWxpemF0aW9uCmxpYnJhcnkoRFQpICAgICAgICAgIyBEaXNwbGF5aW5nIHRhYmxlcwpsaWJyYXJ5KGdncmlkZ2VzKSAgICMgVmlzdWFsaXphdGlvbiBmb3IgZGVuc2l0eSBwbG90cwpsaWJyYXJ5KGdncGxvdDIpICAgICMgRGF0YSB2aXN1YWxpemF0aW9uCmxpYnJhcnkodmlyaWRpcykgICAgIyBDcmVhdGluZyB2aXN1YWxseSBhcHBlYWxpbmcgY29sb3Igc2NhbGVzCmxpYnJhcnkoaHJicnRoZW1lcykgIyBBZGRpdGlvbmFsIHRoZW1lcyBhbmQgdXRpbGl0aWVzIGZvciBnZ3Bsb3QyIHBsb3RzCmBgYAoKIyAgey50YWJzZXQgLnRhYnNldC1kcm9wZG93bn0KCiMjICoqQWJzdHJhY3QqKiB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxscyB9CgpXaGVuIHRoZSB0ZWN0b25pYyBwbGF0ZSBib3VuZGFyaWVzIHdlcmUgZmlyc3QgcmVjb2duaXNlZCwgdGhleSB3ZXJlIGlkZW50aWZpZWQgYnkgc2V2ZXJhbCBmYWN0b3JzLCBvbmUgb2Ygd2hpY2ggaW5jbHVkZWQgcGF0dGVybnMgb2JzZXJ2ZWQgZnJvbSBzZWlzbWljIGFjdGl2aXR5IGRhdGEuIFRoZSBkYXRhIGluaGVyZW50bHkgbWFya3MgcmVnaW9ucyBvZiBzZWlzbWljIGFjdGl2aXR5IHdoZXJlIHRoZSB0ZWN0b25pYyBmb3JjZXMgY29udmVyZ2UgYW5kIGl0IGlzIHdpZGVseSBrbm93biB0aGF0ICBzZWlzbWljIGV2ZW50cyBhcmUgYXNzb2NpYXRlZCB3aXRoIGFsbCB0ZWN0b25pYyBwbGF0ZSBib3VuZGFyaWVzLiBJbiB0aGlzIHN0dWR5LCBJIHdpbGwgZXhwbG9yZSB0aGUgY29tcGxleCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgc2Vpc21pYyBlbmVyZ3kgYW5kIGl0cyBwbGF0ZSBwcm94aW1pdHkuIE1ha2luZyB1c2Ugb2YgYSBzZWlzbWljIGV2ZW50IGRhdGFzZXQgZnJvbSB0aGUgeWVhciBvZiAyMDIzIGFuZCBhIGRhdGFzZXQgY29udGFpbmluZyBnZW9ncmFwaGljIGNvb3JkaW5hdGVzIHRoYXQgY29tcGxldGVseSBlbmNsb3NlIGFsbCB0ZWN0b25pYyBwbGF0ZSBib3VuZGFyaWVzLCBJIGludmVzdGlnYXRlIGhvdyBzZWlzbWljIG1hZ25pdHVkZSByZWxhdGVzIHRvIHRoZSBwcm94aW1pdHkgb2YgYSBwbGF0ZSBib3VuZGFyeS4gQnkgZXhhbWluaW5nIG92ZXIgMjYsMDAwIHJlY29yZGVkIHNlaXNtaWMgZXZlbnRzIHdpdGggdGhlIHVzZSBvZiB2YXJpb3VzIGRhdGEgcHJlcHJvY2Vzc2luZyBtZXRob2RzIEkgYmVnaW4gdG8gdW5kZXJzdGFuZCB0aGUgYmVoYXZpb3Igb2Ygb3VyIGRhdGEsIGFzc2VtYmxlIHNldmVyYWwgdmlzdWFsaXphdGlvbnMgdG8gb2JzZXJ2ZSB0aGUgYmVoYXZpb3IgYW5kIGlkZW50aWZ5IHBhdHRlcm5zIGFuZCByZWxhdGlvbnNoaXBzLiBXaXRoIHRob3NlIHJlbGF0aW9uc2hpcHMgSSB3aWxsIGNvbXBhcmUgZGlmZmVyZW50IHByZWRpY3RpdmUgYW5hbHlzaXMgbWV0aG9kcyBhbmQgdW5jb3ZlciB0aGUgZGV0YWlsZWQgZHluYW1pY3MgdGhvc2UgcmVsYXRpb25zaGlwcyBob2xkLiBXaXRoIHRoZSB1c2Ugb2YgdGhlIGRlY2lzaW9uIHRyZWUtYmFzZWQgbW9kZWwgUmFuZG9tIEZvcmVzdCwgdGhlIHJlc3VsdHMgaW5kaWNhdGUgdGhlIHNlaXNtaWMgbWFnbml0dWRlIHRoYXQgY2FuIGJlIGlkZW50aWZpZWQgd2l0aCB0aGUgcGxhdGUgcHJveGltaXR5IHVzaW5nIHRoZSBleHRyZW1lIHZhbHVlIHRoZW9yZW0uIEl0IHByb3ZpZGVzIGluaXRpYWwgaW5zaWdodCBpbnRvIHVuZGVyc3RhbmRpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBzZWlzbWljIG1hZ25pdHVkZSBsZXZlbCBhbmQgaXRzIHBsYXRlIHByb3hpbWl0eS4KCgoKIyMgKipJbnRyb2R1Y3Rpb24qKiB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxscyB9CgpCZWluZyBib3JuIGFuZCByYWlzZWQgaW4gSWNlbGFuZCwg4oCcdGhlIGxhbmQgb2YgZmlyZSBhbmQgaWNl4oCdLCBJIGhhdmUgYmVlbiBleHBvc2VkIHRvIG11bHRpcGxlIHNlaXNtaWMgYWN0aXZpdGllcywgd2hpY2ggc3BhcmtlZCBpbnRlcmVzdCBpbiB0aGUgc2NpZW5jZSBvZiBzZWlzbW9sb2d5LiBJY2VsYW5kIGlzIGxvY2F0ZWQgaW4gYmV0d2VlbiB0d28gdGVjdG9uaWMgcGxhdGVzLCB0aGUgRXVyYXNpYW4gcGxhdGUgYW5kIHRoZSBOb3J0aCBBbWVyaWNhbiBQbGF0ZSBhbmQgZXhwZXJpZW5jZXMgZnJlcXVlbnQgc2Vpc21pYyBhY3Rpdml0eSBkdWUgdG8gaXRzIHRlY3RvbmljIHNldHRpbmcuIFdoZW4gdGhlIHBsYXRlIGJvdW5kYXJpZXMgd2VyZSBmaXJzdCBkaXNjb3ZlcmVkIGFuZCBkcmF3biBvbiBhIG1hcCwgc2NpZW50aXN0cyBkcmV3IHRoZSBib3VuZGFyaWVzIGFsb25nIGFyZWFzIG9mIGhpZ2ggc2Vpc21pY2l0eSwgc28gaXQgaXMgd2lkZWx5IGtub3duIHRoYXQgc2Vpc21pYyBhY3Rpdml0eSBpcyBoaWdobHkgY29ycmVsYXRlZCB3aXRoIHRoZSB0ZWN0b25pYyBwbGF0ZXMgKFdpbHNvbiwgMjAyMSkuIFRoZXJlIGFyZSB0aHJlZSBkaWZmZXJlbnQgdHlwZXMgb2YgcGxhdGUgYm91bmRhcmllcy4gQSDigJxjb252ZXJnZW504oCdIHBsYXRlIGJvdW5kYXJ5LCB3aGVyZSB0aGUgY3J1c3RzIGNvbWUgdG9nZXRoZXIgYW5kIGNvbGxpZGUuIEluIHNvbWUgY2FzZXMsIGFuIGV2ZW50IGNhbGxlZCDigJxzdWJkdWN0aW9u4oCdIG9jY3VycyB3aGVyZSBvbmUgdGVjdG9uaWMgcGxhdGUgZGl2ZXMgdW5kZXJuZWF0aCB0aGUgb3RoZXIuIFRoZSBzZWNvbmQgdHlwZSBpcyBhIOKAnGRpdmVyZ2VudOKAnSBwbGF0ZSBib3VuZGFyeS4gV2hlcmUgdGhlIHR3byB0ZWN0b25pYyBwbGF0ZXMgc3ByZWFkIGFwYXJ0IGFuZCBvZnRlbiBjYW4gZm9ybSBhIHJpZGdlLiBUaGUgdGhpcmQgdHlwZSBpcyBhIOKAnHRyYW5zZm9ybeKAnSBwbGF0ZSBib3VuZGFyeS4gVGhlIHR3byBjcnVzdHMgc2xpZGUgcGFzdCBvbmUgYW5vdGhlciwgaG9yaXpvbnRhbGx5IChOYXRpb25hbCBHZW9ncmFwaGljIFNvY2lldHksIDIwMjQpLgogCiBJbiBOb3ZlbWJlciBvZiAyMDIzLCB0aGUgdG93biBvZiBHcmluZGF2w61rIG5lYXIgdGhlIFJleWtqYW5lcyBQZW5pbnN1bGEgb2YgSWNlbGFuZCBlbmNvdW50ZXJlZCBudW1lcm91cyBzZWlzbWljIGV2ZW50cy4gRHVyaW5nIHRoZSB3ZWVrIG9mIE5vdmVtYmVyIDd0aCB0byAxNHRoLCBhcHByb3hpbWF0ZWx5IDEzLDcwMCBzZWlzbWljIGV2ZW50cyB3ZXJlIHJlY29yZGVkIHdpdGggb3ZlciAxLDAwMCBiZWluZyBzaWduaWZpY2FudC4gVGhpcyBzaWduaWZpY2FudCBzZWlzbWljIGFjdGl2aXR5IGlzIHdoYXQgaW5zcGlyZWQgbXkgaW50ZXJlc3QgaW4gZXhwbG9yaW5nIHRoaXMgdG9waWMgZnVydGhlci4gRmlndXJlIDEgSGlnaGxpZ2h0cyB0aGUgZXh0ZW50IHRoYXQgdGhlIGRhbWFnZSBvY2N1cnJlZCBhbmQgc2hvd3MgdGhlIGZpc3N1cmUgdGhhdCBoYWQgZW1lcmdlZCB0aHJvdWdoIHRoZSB0b3duLiBUaGUgdG93biBoYXMgcmVtYWluZWQgZXZhY3VhdGVkIHNpbmNlICjigJxWaWt1bGVnIEphcsOwc2tqw6FsZnRheWZpcmxpdOKAnSBuLmQuKS4gCgohWyoqRmlndXJlIDE6KiogRmlzc3VyZSBjYXVzZWQgYnkgc2Vpc21pYyBhY3Rpdml0eSBpbiB0aGUgdG93biBvZiBHcmluZGF2w61rLCBJY2VsYW5kIGluIE5vdmVtYmVyIDIwMjMuIFRoZSBkYW1hZ2UgaWxsdXN0cmF0ZXMgdGhlIHNldmVybmVzcyBvZiBzZWlzbWljIGV2ZW50cyBpbiB0aGUgdG93bl0oSW1hZ2VzL0dyaW5kYXZpay5qcGVnKQpTZWlzbW9sb2d5IGJlY2FtZSBpdHMgb3duIHNjaWVuY2UgaW4gdGhlIGxhdGUgbmluZXRlZW50aCBjZW50dXJ5IGFuZCBzaW5jZSB0aGVuIHRoZXJlIGhhcyBiZWVuIGEgbG90IG9mIHJlc2VhcmNoIGFib3V0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgZGVwdGhzIG9mIHNlaXNtaWMgZXZlbnRzIGFuZCBwbGF0ZSBib3VuZGFyaWVzIChBZ25ldywgMTk4OSkuIE1vc3QgZXZlbnRzIG9jY3VyIG9uIHBsYXRlIGJvdW5kYXJpZXMgYnV0IGl0IGlzIGRlcGVuZGVudCBvbiB0aGUgdHlwZSwgaG93IGRlZXAgdGhlIGV2ZW50IGdvZXMuIEZvciBleGFtcGxlLCBhY2NvcmRpbmcgdG8gV2lsc29uICgyMDIxKSwg4oCcVHJhbnNmb3JtIGJvdW5kYXJpZXMgdGVuZCB0byBoYXZlIHN0ZWVwZXIgcnVwdHVyZSBzdXJmYWNlcywgd2hpY2ggY2F1c2UgdGhlIGVhcnRocXVha2VzIHRvIG9jY3VyIGluIGEgbmFycm93IHpvbmUgYW5kIGxpbWl0cyB0aGVpciBzaXpl4oCdLiBBcyBtZW50aW9uZWQgZWFybGllciwgc3ViZHVjdGlvbiBvY2N1cnMgd2hlbiBvbmUgY3J1c3QgZ29lcyBiZW5lYXRoIGFub3RoZXIuIEl0cyBzZWlzbWljIGFjdGl2aXR5IGlzIHZlcnkgYWJ1bmRhbnQgYW5kIGNhdXNlcyBncmVhdGVyIGRlcHRoIGluIHRoZSBjcnVzdCB0aGFuIGluIG90aGVyIHBsYXRlIGJvdW5kYXJpZXMgKFdpbHNvbiwgMjAyMSkuIFRoZXJlIGlzIGFsc28gYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBpbnRlbnNpdHkgb2YgdGhlIHNlaXNtaWMgZXZlbnQgYW5kIGl0cyBkZXB0aC4gV2l0aCBhIGRlZXBlciBldmVudCwgdGhlIGRpc3RhbmNlIGZyb20gdGhlIHNvdXJjZSB0byB0aGUgc3VyZmFjZSBvZiB0aGUgY3J1c3QgaW5jcmVhc2VzIGFuZCB0aGUgc3RyZW5ndGggb2Ygc2hha2luZyBkaW1pbmlzaGVzLiBDb25zZXF1ZW50bHksIHR3byBldmVudHMgd2l0aCBlcXVhbCBzdHJlbmd0aCBidXQgdmFyeWluZyBkZXB0aHMgY2FycnkgZGlmZmVyZW50IGxldmVscyBvZiBtYWduaXR1ZGUgKOKAnEF0IHdoYXQgZGVwdGggZG8gZWFydGhxdWFrZXMgb2NjdXI/IFdoYXQgaXMgdGhlIHNpZ25pZmljYW5jZSBvZiB0aGUgZGVwdGg/4oCdLCBuLmQpLiAKCldoaWxlIGl0IGhhcyBiZWVuIGVzdGFibGlzaGVkIHRoYXQgdGhlIG1ham9yaXR5IG9mIHNlaXNtaWMgZXZlbnRzIGxpZSBiZXR3ZWVuIHRoZSBwbGF0ZSBib3VuZGFyaWVzLCB0aGVyZSByZW1haW5zIGEgc3Vic2V0IG9mIGV2ZW50cyB0aGF0IG9jY3VyIGZhciBhd2F5IGZyb20gdGhlc2UgYm91bmRhcmllcy4gU2hhbGxvdyBldmVudHMgY2FuIHlpZWxkIHRvIGEgZ3JlYXRlciBpbXBhY3QgaG93ZXZlciwgdGhlIHF1ZXN0aW9uIHJlbWFpbnM6IGRvIHNlaXNtaWMgZXZlbnRzIHRoYXQgb2NjdXIgZnVydGhlciBhd2F5IGZyb20gcGxhdGUgYm91bmRhcmllcyBhbHNvIGV4aGliaXQgaGlnaCBtYWduaXR1ZGVzPyBJbiB0aGlzIHN0dWR5LCBJIGRlbHZlIGludG8gc2Vpc21pYyBldmVudCBkYXRhc2V0IGZyb20gdGhlIHllYXIgb2YgMjAyMyB0byB1bmRlcnN0YW5kIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHNlaXNtaWMgbWFnbml0dWRlIGFuZCB0aGVpciBwcm94aW1pdHkgdG8gcGxhdGUgYm91bmRhcmllcy4KCgoKIyMgKipNZXRob2RzKiogey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHMgfQoKIyMjIERhdGEgUHJlcHJvY2Vzc2luZwoKYGBge3IgZGF0YWxvYWQsIGluY2x1ZGU9RkFMU0V9CmVhcnRocXVha2VfcGxhdGVzX2RmID0gcmVhZC5jc3YoIkVhcnRxdWFrZXNfd19wbGF0ZXMuY3N2IikKY29sbmFtZXMoZWFydGhxdWFrZV9wbGF0ZXNfZGYpW2NvbG5hbWVzKGVhcnRocXVha2VfcGxhdGVzX2RmKSA9PSAibWluX2Rpc3RhbmNlX3RvX3RlY3RvbmljX3BsYXRlIl0gPC0gImRpc3RhbmNlIgphdHRhY2goZWFydGhxdWFrZV9wbGF0ZXNfZGYpCiNzdHIoZWFydGhxdWFrZV9wbGF0ZXNfZGYpCmBgYAoKSSBhY3F1aXJlZCBhIGRhdGFzZXQgZG9jdW1lbnRpbmcgZ2xvYmFsIHNlaXNtaWMgZXZlbnRzIHRocm91Z2hvdXQgdGhlIHllYXIgMjAyNCBmcm9tIEthZ2dsZS5jb20uIFRoZSBkYXRhc2V0IGluY2x1ZGVzIG92ZXIgMjIgYXR0cmlidXRlcywgcHJvdmlkaW5nIGluZm9ybWF0aW9uIG9uIG1vcmUgdGhhbiAyNiwwMDAgcmVjb3JkZWQgc2Vpc21pYyBldmVudHMuIEtleSBhdHRyaWJ1dGVzIGluY2x1ZGUgbWFnbml0dWRlLCB0aW1lLCBkZXB0aCBhbmQgZ2VvZ3JhcGhpYyBjb29yZGluYXRlcyBvZiBlYWNoIGV2ZW50LiBIb3dldmVyLCBhcyB0aGUgZGF0YXNldCBsYWNrZWQgaW5mb3JtYXRpb24gYWJvdXQgdGVjdG9uaWMgcGxhdGVzLCBJIG9idGFpbmVkIGFuIGFkZGl0aW9uYWwgZGF0YXNldCBjb250YWluaW5nIHRoZSBnZW9ncmFwaGljIGNvb3JkaW5hdGVzIG9mIGFsbCB0ZWN0b25pYyBwbGF0ZXMsIG1ham9yIGFuZCBtaW5vciwgYWxvbmcgd2l0aCB0aGVpciByZXNwZWN0aXZlIG5hbWVzIChLZXNlciwgMjAyMzsgVGhvbXBzb24sIDIwMjApLiBBbiBpbGx1c3RyYXRpb24gb2YgdGhlIGVhcnRo4oCZcyBsaXRob3NwaGVyZSB3aXRoIHRoZSBtYXJraW5nIG9mIGFsbCBwbGF0ZSBib3VuZGFyaWVzIGlzIHNob3duIGluIGZpZ3VyZSAyLiAKCiFbRmlndXJlIDI6IE1hcCBpbGx1c3RyYXRpbmcgYWxsIG1ham9yIGFuZCBtaW5vciB0ZWN0b25pYyBwbGF0ZSBib3VuZGFyaWVzLl0oSW1hZ2VzL2VhcnRoLXMtdGVjdG9uaWMtcGxhdGVzLmpwZWcpCgpUaGUgbWFqb3JpdHkgb2YgdGhlIGRhdGEgcHJlcHJvY2Vzc2luZyBtZXRob2RzIHdlcmUgdXNlZCB1c2luZyBweXRob247IGRldGFpbHMgb2YgdGhlIGNvZGUgY2FuIGJlIGZvdW5kIGluIHRoZSBhcHBlbmRpeC4gSW5pdGlhbGx5LCB0aGUgZGF0YXNldCBjb250YWluZWQgb3ZlciAyNiwwMDAgZW50cmllcy4gSG93ZXZlciwgdG8gZW5zdXJlIHRoZSBhY2N1cmFjeSBvZiB0aGUgZGF0YSwgZW50cmllcyB3aXRoIG1pc3NpbmcgdmFsdWVzIHdlcmUgcmVtb3ZlZCByZXN1bHRpbmcgaW4gYXBwcm94aW1hdGVseSAyMiwwMDAgdmFsaWQgb2JzZXJ2YXRpb25zLiAKClRvIGludmVzdGlnYXRlIHRoZSBwcm94aW1pdHkgb2Ygc2Vpc21pYyBldmVudHMgdG8gdGVjdG9uaWMgcGxhdGVzLCBhIG5ldyBhdHRyaWJ1dGUgbmFtZWQg4oCcZGlzdGFuY2XigJ0gd2FzIGNyZWF0ZWQsIGNhbGN1bGF0ZWQgdXNpbmcgdGhlIEhhdmVyc2luZSBGb3JtdWxhLiBUaGlzIG1hdGhlbWF0aWNhbCBmb3JtdWxhIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBzaG9ydGVzdCBkaXN0YW5jZSBiZXR3ZWVuIHR3byBwb2ludHMgb24gdGhlIHN1cmZhY2Ugb2YgYSBzcGhlcmUgaW4ga2lsb21ldGVyczoKCgpcWwphID0gXHNpbl4yXGxlZnQoXGZyYWN7XERlbHRhIGxhdH17Mn1ccmlnaHQpICsgXGNvcyhsYXRfMSkgXGNkb3QgXGNvcyhsYXRfMikgXGNkb3QgXHNpbl4yXGxlZnQoXGZyYWN7XERlbHRhIGxvbn17Mn1ccmlnaHQpClxdCgpcWwpjID0gMiBcY2RvdCBcdGV4dHthdGFuMn1cbGVmdChcc3FydHthfSwgXHNxcnR7MS1hfVxyaWdodCkKXF0KClxbCmQgPSBSIFxjZG90IGMKXF0KCldoZXJlIFwoIGQgXCkgaXMgdGhlIGRpc3RhbmNlIGJldHdlZW4gdGhlIHR3byBwb2ludHMgKGFsb25nIHRoZSBzdXJmYWNlIG9mIHRoZSBzcGhlcmUpLCBcKCBcRGVsdGEgbGF0IFwpIGlzIHRoZSBkaWZmZXJlbmNlIGluIGxhdGl0dWRlIGJldHdlZW4gdGhlIHR3byBwb2ludHMsIFwoIFxEZWx0YSBsb24gXCkgaXMgdGhlIGRpZmZlcmVuY2UgaW4gbG9uZ2l0dWRlIGJldHdlZW4gdGhlIHR3byBwb2ludHMsIFwoIFIgXCkgaXMgdGhlIHJhZGl1cyBvZiB0aGUgc3BoZXJlICg2LDM3MSBraWxvbWV0ZXJzKSwgXCggbGF0XzEgXCkgYW5kIFwoIGxvbl8yIFwpIGFyZSB0aGUgbGF0aXR1ZGVzIG9mIHRoZSB0d28gcG9pbnRzIGluIHJhZGlhbnMsIFwoIFx0ZXh0e2F0YW4yfSBcKSBpcyB0aGUgdHdvLWFyZ3VtZW50IGFyY3RhbmdlbnQgZnVuY3Rpb24gKFVwYWRoeWF5LCAyMDI0KS4gCgpUaGUgcmVzdCBvZiB0aGUgcHJlcHJvY2Vzc2luZyBzdGVwcyB3ZXJlIHBlcmZvcm1lZCBpbiBSU3R1ZGlvLiBUaGVzZSBzdGVwcyBpbnZvbHZlIHJlbW92aW5nIHVubmVjZXNzYXJ5IGF0dHJpYnV0ZXMgYW5kIGFkanVzdGluZyBkYXRhIHR5cGVzIHRvIHNpbXBsaWZ5IGZ1cnRoZXIgcmVzZWFyY2guIFRoZSB0YWJsZSBiZWxvdyBvdXRsaW5lcyB0aGUgYXR0cmlidXRlcyBvZiB0aGUgZGF0YSB0aGF0IHdpbGwgYmUgdXRpbGl6ZWQgaW4gdGhpcyBzdHVkeS4gCgoKYGBge3IgY2xlYW4gZGF0YX0KIyBSZW1vdmluZyB1bm5lY2Vzc2FyeSBjb2x1bW5zIChpZCAmIHVwZGF0ZWQpCkVhcnRocXVha2VzIDwtIGVhcnRocXVha2VfcGxhdGVzX2RmWywgYygidGltZSIsICJsYXRpdHVkZSIsICJsb25naXR1ZGUiLCAiZGVwdGgiLCAibWFnIiwgInR5cGUiLCAiYXJlYSIsICJkaXN0YW5jZSIsICJwbGF0ZV9sYXRpdHVkZSIsICJwbGF0ZV9sb25naXR1ZGUiLCAicGxhdGVfbmFtZSIpXQoKIyBNYWtpbmcgYSBkYXRhZnJhbWUgd2l0aCBvbmx5IGVhcnRocXVha2VzICgyNiw0MjgpCiAgIyBvbmx5IGluY2x1ZGluZyBtYWduaXR1ZGUgb2YgNC41IGFuZCBhYm92ZQpkZiA9IEVhcnRocXVha2VzICU+JQogIGZpbHRlcih0eXBlID09ICJlYXJ0aHF1YWtlIikgJT4lIAogIGZpbHRlcihtYWcgPiA0LjQ5OSkKCiMgQ29udmVydGluZyBjb2x1bW4gdHlwZXMKZGYkdGltZSA8LSBhcy5QT1NJWGN0KGRmJHRpbWUsIGZvcm1hdD0iJVktJW0tJWRUJUg6JU06JU9TWiIsIHR6ID0gIlVUQyIpCmRmJG1hZyA9IGFzLm51bWVyaWMoZGYkbWFnKQpkZiR0eXBlID0gYXMuZmFjdG9yKGRmJHR5cGUpCmBgYAoKCmBgYHtyIHRhYmxlLCBlY2hvPUZBTFNFfQojIE1ha2luZyBhIHRhYmxlIHRoYXQgbGlzdHMgYSBkaWVzY3JpcHRpb24gb2YgYWxsIGNvbHVtbnMKbGlicmFyeShEVCkKRGVzIDwtIGRhdGEuZnJhbWUoCiAgQ29sdW1uID0gYygiVGltZSIsICJMYXRpdHVkZS9Mb25naXR1ZGUiLCAiRGVwdGgiLCAiTWFnIiwgIkRpc3RhbmNlIiwgIlBsYXRlIG5hbWUiLCAiQXJlYSIpLAogIFR5cGUgPSBjKCJQT1NJWGN0IiwgIk51bWVyaWMiLCAiTnVtZXJpYyIsICJOdW1lcmljIiwgIkNoYXJhY3RlciIsICJOdW1lcmljIiwgIkNoYXJhY3RlciIpLAogIERlc2NyaXB0aW9uID0gYygKICAgICJEYXRlIGFuZCB0aW1lIG9mIHRoZSBldmVudCIsCiAgICAiR2VvZ3JhcGhpYyBjb29yZGluYXRlcyBvZiB0aGUgbG9jYXRpb24gb2YgdGhlIGV2ZW50IiwKICAgICJUaGUgZGVwdGggb2YgdGhlIGV2ZW50IGluIGtpbG9tZXRlcnMiLAogICAgIk1hZ25pdHVkZSB2YWx1ZSAoUmljaHRlciBTY2FsZSkiLAogICAgIlRoZSBkaXN0YW5jZSB0byB0aGUgbmVhcmVzdCB0ZWN0b25pYyBwbGF0ZSBpbiBraWxvbWV0ZXJzIiwKICAgICJQbGF0ZSBuZWFyZXN0IHRvIHRoZSBzZWlzbWljIGV2ZW50IiwKICAgICJUaGUgcmVnaW9uIHdoZXJlIHRoZSBzZWlzbWljIGV2ZW50IG9jY3VycyIpCiAgKQoKZGF0YXRhYmxlKERlcywgcm93bmFtZXMgPSBUUlVFLCBjYXB0aW9uID0gJ0NvbHVtbiBEZXNjcmlwdGlvbicsIG9wdGlvbnMgPSBsaXN0KHRoZW1lID0gJ2Jvb3RzdHJhcCcpKQpgYGAKCiMjIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzIH0KCkJlZm9yZSBkaXZpbmcgaW50byBjb21wbGV4IGFuYWx5c2lzLCBJIGNvbmR1Y3RlZCBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpIHRvIHVuZGVyc3RhbmQgdGhlIHN0cnVjdHVyZSBhbmQgZGlzdHJpYnV0aW9uIG9mIHRoZSBkYXRhc2V0LiBFREEgc2VydmVzIGFzIGEgY3J1Y2lhbCBzdGVwIGluIHVuZGVyc3RhbmRpbmcgdGhlIHVuZGVybHlpbmcgcGF0dGVybnMgYW5kIHJlbGF0aW9uc2hpcCB3aXRoIHRoZSBkYXRhLgoKCi0gSXQgaXMgcmVjb21tZW5kZWQgdG8gc2Nyb2xsIGRvd24gdG8gdGhlIGJvdHRvbSBvZiB0aGUgc2hlZXQgYW5kIGNsaWNrIHRoZSBidXR0b24gdGhhdCBzYXlzICpDaGFuZ2UgZGlzcGxheSBzZXR0aW5ncyogYW5kIGNob29zZSAqZGVza3RvcCBsYXlvdXQqLiBUaGVuIHlvdSBzaG91bGQgc2VlIHRoZSB2aXN1YWxpemF0aW9ucyBhcyBkZXNpcmVkLgoKCjxkaXYgY2xhc3M9J3RhYmxlYXVQbGFjZWhvbGRlcicgaWQ9J3ZpejE3MTQ1MjUzNjk2NTQnIHN0eWxlPSdwb3NpdGlvbjogcmVsYXRpdmUnPjxub3NjcmlwdD48YSBocmVmPScjJz48aW1nIGFsdD0nICcgc3JjPSdodHRwczomIzQ3OyYjNDc7cHVibGljLnRhYmxlYXUuY29tJiM0NztzdGF0aWMmIzQ3O2ltYWdlcyYjNDc7Q2EmIzQ3O0NhcHN0b25lUHJvamVjdF8xNzE0NTI1MDE3MDkwMCYjNDc7TWFnbml0dWRlRGlzdHJpYnV0aW9uJiM0NzsxX3Jzcy5wbmcnIHN0eWxlPSdib3JkZXI6IG5vbmUnIC8+PC9hPjwvbm9zY3JpcHQ+PG9iamVjdCBjbGFzcz0ndGFibGVhdVZpeicgIHN0eWxlPSdkaXNwbGF5Om5vbmU7Jz48cGFyYW0gbmFtZT0naG9zdF91cmwnIHZhbHVlPSdodHRwcyUzQSUyRiUyRnB1YmxpYy50YWJsZWF1LmNvbSUyRicgLz4gPHBhcmFtIG5hbWU9J2VtYmVkX2NvZGVfdmVyc2lvbicgdmFsdWU9JzMnIC8+IDxwYXJhbSBuYW1lPSdzaXRlX3Jvb3QnIHZhbHVlPScnIC8+PHBhcmFtIG5hbWU9J25hbWUnIHZhbHVlPSdDYXBzdG9uZVByb2plY3RfMTcxNDUyNTAxNzA5MDAmIzQ3O01hZ25pdHVkZURpc3RyaWJ1dGlvbicgLz48cGFyYW0gbmFtZT0ndGFicycgdmFsdWU9J3llcycgLz48cGFyYW0gbmFtZT0ndG9vbGJhcicgdmFsdWU9J3llcycgLz48cGFyYW0gbmFtZT0nc3RhdGljX2ltYWdlJyB2YWx1ZT0naHR0cHM6JiM0NzsmIzQ3O3B1YmxpYy50YWJsZWF1LmNvbSYjNDc7c3RhdGljJiM0NztpbWFnZXMmIzQ3O0NhJiM0NztDYXBzdG9uZVByb2plY3RfMTcxNDUyNTAxNzA5MDAmIzQ3O01hZ25pdHVkZURpc3RyaWJ1dGlvbiYjNDc7MS5wbmcnIC8+IDxwYXJhbSBuYW1lPSdhbmltYXRlX3RyYW5zaXRpb24nIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2Rpc3BsYXlfc3RhdGljX2ltYWdlJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdkaXNwbGF5X3NwaW5uZXInIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2Rpc3BsYXlfb3ZlcmxheScgdmFsdWU9J3llcycgLz48cGFyYW0gbmFtZT0nZGlzcGxheV9jb3VudCcgdmFsdWU9J3llcycgLz48cGFyYW0gbmFtZT0nbGFuZ3VhZ2UnIHZhbHVlPSdlbi1VUycgLz48L29iamVjdD48L2Rpdj4KCgoKYGBge2pzIFRhYmxlYXUsIGVtYmVkY29kZSwgZWNobz1GQUxTRX0KdmFyIGRpdkVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndml6MTcxNDUyNTM2OTY1NCcpOwp2YXIgdml6RWxlbWVudCA9IGRpdkVsZW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ29iamVjdCcpWzBdOwp2aXpFbGVtZW50LnN0eWxlLndpZHRoPScxMDAlJzt2aXpFbGVtZW50LnN0eWxlLmhlaWdodD0oZGl2RWxlbWVudC5vZmZzZXRXaWR0aCowLjc1KSsncHgnOwp2YXIgc2NyaXB0RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpOwpzY3JpcHRFbGVtZW50LnNyYyA9ICdodHRwczovL3B1YmxpYy50YWJsZWF1LmNvbS9qYXZhc2NyaXB0cy9hcGkvdml6X3YxLmpzJzsKdml6RWxlbWVudC5wYXJlbnROb2RlLmluc2VydEJlZm9yZShzY3JpcHRFbGVtZW50LCB2aXpFbGVtZW50KTsKYGBgCgojIyMjIE1hZ2l0dWRlIERpc3RyaWJ1dGlvbgoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBzZWlzbWljIG1hZ25pdHVkZXMgaXMgcmVwcmVzZW50ZWQgaW4gZmlndXJlICpNYWduaXR1ZGUgRGlzdHJpYnV0aW9uKiB0aHJvdWdoIGFuIGFyZWEgcGxvdC4gVXBvbiBleGFtaW5hdGlvbiBJIG9ic2VydmVkIGFuIGlycmVndWxhciBhbmQgaW5jb25zaXN0ZW50IHBhdHRlcm4gdXAgdG8gdGhlIHZhbHVlIG9mIDQuNS4gVGhpcyBvYnNlcnZhdGlvbiBsZWQgbWUgdG8gYmVsaWV2ZSB0aGF0IHRoZSByZWxpYWJpbGl0eSBvZiB0aGVzZSBkYXRhIHBvaW50cyB3ZXJlIHF1ZXN0aW9uYWJsZS4gQ29uc2VxdWVudGx5LCBhbGwgZGF0YSBwb2ludHMgYmVsb3cgYSBtYWduaXR1ZGUgb2YgNC41IGhhdmUgYmVlbiBleGNsdWRlZCBmcm9tIHRoZSBkYXRhc2V0LiBUaGUgYW5hbHlzaXMgd2lsbCBmb2N1cyBtb3JlIG9uIHNpZ25pZmljYW50IHNlaXNtaWMgZXZlbnRzLCBlbnN1cmluZyBtb3JlIHJvYnVzdCByZXNlYXJjaC4gTGVmdCBhcmUgYXBwcm94aW1hdGVseSA4LDYwMCBvYnNlcnZhdGlvbnMuCgpUaGUgdGFibGUgYmVsb3cgb3V0bGluZXMgdGhlIHN1bW1hcnkgc3RhdGlzdGljcyBvZiB0aGUga2V5IGF0dHJpYnV0ZXMuIEFzIHByZXZpb3VzbHkgbWVudGlvbmVkLCB0aGUgbWluaW11bSBtYWduaXR1ZGUgcmVjb3JkZWQgaXMgNC41LiBJbnRlcmVzdGluZ2x5LCBib3RoIHRoZSBtZWFuIGFuZCB0aGUgbWVkaWFuIHZhbHVlcyBhcmUgc2ltaWxhciB0byB0aGUgbWluaW11bSB2YWx1ZS4gU2ltaWxhcmx5LCBmb3IgdGhlIGRlcHRoIGFuZCB0aGUgZGlzdGFuY2UsIHRoZWlyIG1lYW4gYW5kIG1lZGlhbiB2YWx1ZXMgYWxpZ24gY2xvc2VseSB0byB0aGUgbWluaW11bSB2YWx1ZS4gVGhlc2Ugc3VtbWFyaWVzIGluZGljYXRlIHRoYXQgYSBsYXJnZSBwb3J0aW9uIG9mIHRoZSBkYXRhIHBvaW50cyBhcmUgY2x1c3RlcmVkIGNsb3NlbHkgdG8gdGhlIG1pbmltdW0gdmFsdWVzLiAKCmBgYHtyIHN1bW1hcnksIGVjaG89RkFMU0V9CnN1bW1hcnkoZGZbLCBjKDQsIDUsIDgpXSkKYGBgCgojIyMjIERlcHRoIERpc3RyaWJ1dGlvbiBNYXAKCgpWaXN1YWxpemF0aW9ucyBwbGF5IGFuIGltcG9ydGFudCByb2xlIGluIEVEQSwgYWxsb3dpbmcgdXMgdG8gaWRlbnRpZnkgdHJlbmRzLCBvdXRsaWVycyBhbmQgcG90ZW50aWFsIHJlbGF0aW9uc2hpcHMgaW4gb3VyIGF0dHJpYnV0ZXMuIEZpZ3VyZSAqRGVwdGggRGlzdHJpYnV0aW9uIE1hcCogZGlzcGxheXMgdGhlIHNlaXNtaWMgZXZlbnRzIGRpc3RyaWJ1dGVkIG9uIGEgbWFwIHdpdGggZWFjaCBwb2ludCByZXByZXNlbnRpbmcgIGFuIGV2ZW50LiBUaGUgc2l6ZSBhbmQgY29sb3IgaW5kaWNhdGUgdGhlIGRlcHRoLCBoaWdobGlnaHRpbmcgdGhlIGRlZXAgZXZlbnRzIGluIHNvdXRoZWFzdCBBc2lhLiBUaGlzIHJlZ2lvbiBjb3JyZXNwb25kcyB0byB0aGUgY29udmVyZ2VuY2Ugb2YgdGhlIEV1cmFzaWFuIGFuZCB0aGUgTm9ydGggQW1lcmljYW4gcGxhdGVzLCBmb3JtaW5nIGEgY29udmVyZ2VudCBwbGF0ZSBib3VuZGFyeSwgcHJvbmUgdG8gc3ViZHVjdGlvbi4gQXMgcHJldmlvdXNseSBtZW50aW9uZWQsIHN1YmR1Y3Rpb24gb2Z0ZW4gcmVzdWx0cyBpbiBncmVhdGVyIGRlcHRocyBjb21wYXJlZCB0byBvdGhlciBwbGF0ZXMuIFRoaXMgdmlzdWFsaXphdGlvbiB0aGVyZWJ5IHN1cHBvcnRzIHRoYXQgb2JzZXJ2YXRpb24uCgojIyMjIEZyZXF1ZW5jeSBvZiBFYXJ0aHF1YWtlcwoKCkZpZ3VyZSAqRnJlcXVlbmN5IG9mIEVhcnRocXVha2VzKiwgc2hvd2Nhc2VzIGEgZGFzaGJvYXJkIGZlYXR1cmluZyBtdWx0aXBsZSB2aXN1YWxpemF0aW9ucyB0aGF0IHdpbGwgaW5jcmVhc2Ugb3VyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIGRhdGEuIEZpZ3VyZSBhLCBleGhpYml0cyB0aGUgc2FtZSBhcmVhIHBsb3Qgc2hvd24gaW4gZmlndXJlIDMsIHRob3VnaCB3aXRoIHRoZSBkYXRhIHBvaW50cyBsZXNzIHRoYW4gNC41IGV4Y2x1ZGVkLiBPdmVyIDMsMDAwIHJlY29yZGVkIG9ic2VydmF0aW9ucyByZWdpc3RlciBhIG1hZ25pdHVkZSBvZiA0LjUsIHJlcHJlc2VudGluZyA0MSUgb2Ygb3VyIGRhdGEgYW5kIGRlbW9uc3RyYXRpbmcgYSByaWdodCBza2V3bmVzcyBpbiB0aGUgZGlzdHJpYnV0aW9uLiBBcyB0aGUgbWFnbml0dWRlIGluY3JlYXNlcywgdGhlIGZyZXF1ZW5jeSBzaGFycGx5IGRlY2xpbmVzLCBzdXBwb3J0aW5nIG91ciBlYXJsaWVyIHN0YXRlbWVudCB0aGF0IGEgc2lnbmlmaWNhbnQgcG9ydGlvbiBvZiB0aGUgZGF0YSBpcyBjbHVzdGVyZWQgY2xvc2VseSBhcm91bmQgdGhlIG1pbmltdW0gdmFsdWVzLgoKRmlndXJlIGIsIGlsbHVzdHJhdGVzIGEgZGVuc2l0eSBtYXAgcmVwcmVzZW50aW5nIHRoZSBhY3Rpdml0eSBhcm91bmQgdGhlIGdsb2JlLiBNZWFud2hpbGUsIGZpZ3VyZSBjIGlsbHVzdHJhdGVzIGEgdGltZSBzZXJpZXMgcGxvdCBzaG93Y2FzaW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNlaXNtaWMgYWN0aXZpdHkgdGhyb3VnaG91dCB0aGUgeWVhciAyMDIzLiBUaGUgdGltZSBzZXJpZXMgcGxvdCBkaXNwbGF5cyBhIGdlbmVyYWxseSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiwgbWFya2VkIGJ5IHRocmVlIG5vdGljZWFibGUgc3Bpa2VzIGluIGFjdGl2aXR5LiBUaGUgdGFsbGVzdCBzcGlrZSBvY2N1cnMgb24gRGVjZW1iZXIgMm5kIGFuZCAzcmQsIHJlY29yZGluZyBvdmVyIDM1MCBzZWlzbWljIGV2ZW50cyBzb2xlbHkgaW4gdGhlIFBoaWxpcHBpbmVzLiBUaGUgaGVpZ2h0ZW5lZCBhY3Rpdml0eSBpcyBub3RpY2VhYmxlIG9uIHRoZSBtYXAsIHBhcnRpY3VsYXJseSBpbiBTb3V0aGVhc3QgQXNpYS4gCgojIyMjIERpc3RhbmNlIGJ5IEFyZWEKCkRpc3BsYXllZCBpbiBmaWd1cmUgKkRpc3RhbmNlIGJ5IEFyZWEqIGFuZCAqUGxhdGUgUHJveGltaXR5IGFuZCBNYWduaXR1ZGUqLCBhcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24gYWJvdXQgdGhlIOKAnGRpc3RhbmNl4oCdIGF0dHJpYnV0ZSBpbiBob3BlIHRvIGhhdmUgYSBiZXR0ZXIgdW5kZXJzdGFuZGluZyBvZiBpdHMgZGlzdHJpYnV0aW9ucyBhbmQgcmVsYXRpb25zaGlwcy4gVGhlIHJlZ2lvbnMgZnVydGhlc3QgYXdheSBmcm9tIHRoZSBwbGF0ZSBib3VuZGFyaWVzIGFyZSBzaG93Y2FzZWQgaW4gYSBiYXJwbG90IGluIGZpZ3VyZSAqRGlzdGFuY2UgYnkgQXJlYSosIHdpdGggZWFjaCBiYXIgbGFiZWxlZCB3aXRoIHRoZSBjb3VudCBvZiBldmVudHMgb2NjdXJyaW5nIHdpdGhpbiB0aGF0IHJlZ2lvbi4gVGhlIG1hcCBzaG93cyB0aGUgc2Vpc21pYyBldmVudHMgd2l0aCB0aGUgc2l6ZXMgY29ycmVzcG9uZGluZyB0byB0aGUgZGlzdGFuY2UuIFRoZSBzZWlzbWljIGV2ZW50IHRoYXQgb2NjdXJyZWQgZnVydGhlc3QgYXdheSBmcm9tIGEgcGxhdGUgaXMgbG9jYXRlZCBpbiB0aGUgRnJlbmNoIFBvbHluZXNpYSBSZWdpb24gd2hpY2ggaXMgbG9jYXRlZCBvbiB0aGUgUGFjaWZpYyBQbGF0ZS4gCgojIyMjIFBsYXRlIFByb3hpbWl0eSBhbmQgTWFnbml0dWRlCgoKSWxsdXN0cmF0ZWQgaW4gZmlndXJlIGEsIHRoZSBiYXIgcGxvdCByZXByZXNlbnRzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGRpc3RhbmNlIGluIHNldHMgb2YgMTAwIGtpbG9tZXRlcnMuIFRoZSBmaXJzdCBiYXIgcmVwcmVzZW50cyBvdmVyIDUsMDAwIGRhdGEgcG9pbnRzIHdoaWNoIGlzIGFwcHJveGltYXRlbHkgNjUlIG9mIG91ciB0b3RhbCBkYXRhIHBvaW50cy4gQXMgcHJldmlvdXNseSBkaXNjdXNzZWQsIHRoZSBtYWpvcml0eSBvZiBzZWlzbWljIGFjdGl2aXR5IGxpZXMgYmV0d2VlbiBvciBjbG9zZSB0byBwbGF0ZSBib3VuZGFyaWVzIHNvIHRoaXMgaW5mb3JtYXRpb24gc2hvdWxkIG5vdCBjb21lIGFzIGEgc3VycHJpc2UuIEFzIHRoZSBkaXN0YW5jZSBpbmNyZWFzZXMsIHRoZSBmcmVxdWVuY3kgZHJhbWF0aWNhbGx5IGRlY3JlYXNlcy4gRnJvbSBhIGNsb3NlciBsb29rLCB1cCB0byAyMCBvYnNlcnZhdGlvbnMgYXJlIG1vcmUgdGhhbiAxLDUwMCBraWxvbWV0ZXJzIGZyb20gdGhlIG5lYXJlc3QgdGVjdG9uaWMgcGxhdGUuIAoKRmlndXJlIGIsIGEga2V5IHZpc3VhbGl6YXRpb24sIHNob3djYXNlcyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc2Vpc21pYyBtYWduaXR1ZGUgYW5kIHBsYXRlIHByb3hpbWl0eSwgYWxzbyBrbm93biBhcyB0aGUgZGlzdGFuY2UuIEluaXRpYWxseSB0aGUgcGxvdCBzdWdnZXN0cyBhIG5lZ2F0aXZlIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIGF0dHJpYnV0ZXMsIGluZGljYXRpbmcgdGhhdCBhcyB0aGUgZGlzdGFuY2UgZnJvbSB0aGUgZXZlbnQgaW5jcmVhc2VzIHRoZSBtYWduaXR1ZGUgZGVjcmVhc2VzLiBIb3dldmVyLCB1cG9uIGNsb3NlciBpbnNwZWN0aW9uLCBpdCBiZWNvbWVzIGV2aWRlbnQgdGhhdCB0aGUgbWFqb3JpdHkgb2YgdGhlIGRhdGEgcG9pbnRzIGNsdXN0ZXIgd2l0aGluIHRoZSByYW5nZSBvZiA0LjUgdG8gNS4wIG1hZ25pdHVkZSBhbmQgMCB0byAxMDAga2lsb21ldGVycyBpbiBkaXN0YW5jZS4gQ29uc2VxdWVudGx5LCBpbXBsZW1lbnRpbmcgYSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gbGVhZHMgdG8gaW5zaWduaWZpY2FudCByZXN1bHRzLiBOb25ldGhlbGVzcywgYXMgaW5pdGlhbGx5IHN1Z2dlc3RlZCwgdGhlIGhpZ2hlc3QgdmFsdWVzIGZvciBlYWNoIG1hZ25pdHVkZSBzZXQsIGluIGluY3JlbWVudHMgb2YgMC4xLCBzaG93IGEgbmVnYXRpdmUgbGluZWFyIHJlbGF0aW9uc2hpcC4gV2l0aCB0aGlzIG9ic2VydmF0aW9uIGluIG1pbmQsIEkgdHVybmVkIHRvIHRoZSBFeHRyZW1lIFZhbHVlIFRoZW9yZW0sIHdoaWNoIHByb3ZpZGVzIGEgbWF0aGVtYXRpY2FsIGZyYW1ld29yayB0byBkZWFsIHdpdGggZXh0cmVtZSBldmVudHMgYW5kIHRoZWlyIHByb2JhYmlsaXRpZXMuIEFkZGl0aW9uYWxseSwgYW4gZXh0cmEgYXR0cmlidXRlIGhhcyBiZWVuIGluY2x1ZGVkIGluIHRoZSBkYXRhc2V0IHRoYXQgYWdncmVnYXRlcyB0aGUgbWF4aW11bSBkaXN0YW5jZSBmb3IgZWFjaCBzZXQgb2YgbWFnbml0dWRlLCBpbiBpbmNyZW1lbnRzIG9mIDAuMS4gCgpgYGB7cn0KIyBDcmVhdGUgYSBjb2x1bW4gbWFnRmFjdG9yLCBpbmNyZW1lbnRzIG9mIDAuMQpicmVha3MgPC0gc2VxKDQuNSwgOC4wLCBieSA9IDAuMSkKbGFiZWxzIDwtIHBhc3RlMChicmVha3NbMTpsZW5ndGgoYnJlYWtzKS0xXSkKZGYkbWFnRmFjdG9yIDwtIGN1dChkZiRtYWcsIGJyZWFrcyA9IGJyZWFrcywgbGFiZWxzID0gbGFiZWxzLCByaWdodCA9IEZBTFNFKQoKIyB1c2luZyBleHRyZW1lIHZhbHVlIHRoZW9yZW0KIyBBZ2dyZWdhdGluZyBoaWdoZXN0IG1pblBsYXRlRGlzdGFuY2UgZm9yIGVhY2ggbWFnRmFjdG9yIGxldmVsCm1heF9kaXN0YW5jZSA8LSBkZiAlPiUKICBncm91cF9ieShtYWdGYWN0b3IpICU+JQogIHN1bW1hcmlzZShtYXhfZGlzdGFuY2UgPSBtYXgoZGlzdGFuY2UpKQoKIyBNZXJnaW5nIGFnZ3JlZ2F0ZWQgZGF0YSBiYWNrIGludG8gb3JpZ2luYWwgZGF0YWZyYW1lCmRmIDwtIGxlZnRfam9pbihkZiwgbWF4X2Rpc3RhbmNlLCBieSA9ICJtYWdGYWN0b3IiKQoKYGBgCgpUaGUgcGxvdCBiZWxvdywgc2hvd2Nhc2VzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgbWF4aW11bSBkaXN0YW5jZSBhbmQgdGhlIHNlaXNtaWMgbWFnbml0dWRlLgoKCmBgYHtyfQpnZ3Bsb3QoZGYsIGFlcyh4ID0gbWFnRmFjdG9yLCB5ID0gbWF4X2Rpc3RhbmNlKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiI2YwYTBkMSIsIHNpemUgPSAzLCBhbHBoYSA9IDAuNikgKyAKICBsYWJzKHggPSAiTWFnbml0dWRlIiwgeSA9ICJNYXhpbXVtIERpc3RhbmNlIikgKwogIGdndGl0bGUoIk1heGltdW0gZGlzdGFuY2UgYnkgU2V0cyBvZiBNYWduaXR1ZGUiKSArCiAgdGhlbWVfaXBzdW0oKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLCAKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIKICApCgpgYGAKCiMjIyMgRnJlcXVlbmN5IGJ5IENvdW50cnkKClRoZSBmaWd1cmUgKkZyZXF1ZW5jeSBieSBDb3VudHJ5KiBpbGx1c3RyYXRlcyB0aGUgZnJlcXVlbmN5IG9mIHNlaXNtaWMgZXZlbnRzIGZvciBlYWNoIGNvdW50cnkuCgojIyMgTW9kZWxpbmcKClRvIGFuc3dlciB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gb2Ygd2hldGhlciBzZWlzbWljIGV2ZW50cyBvY2N1cnJpbmcgZnVydGhlciBmcm9tIHBsYXRlIGJvdW5kYXJpZXMgYWxzbyBleGhpYml0IGhpZ2ggbWFnbml0dWRlcywgSSBjb25kdWN0ZWQgYW5kIGNvbXBhcmVkIHZhcmlvdXMgZGF0YSBtb2RlbGluZyBtZXRob2RzLiBUbyBlbnN1cmUgYW4gdW5iaWFzZWQgZXZhbHVhdGlvbiBvZiB0aGUgbW9kZWxzIHBlcmZvcm1hbmNlLCB0aGUgZGF0YXNldCB3YXMgZGl2aWRlZCBpbnRvIGEgdHJhaW5pbmcgc2V0IGFuZCBhIHRlc3Rpbmcgc2V0LiBUaGUgdHJhaW5pbmcgc2V0IGNvbnRhaW5zIDgwJSBvZiB0aGUgb3JpZ2luYWwgZGF0YSBhbmQgdGhlIHRlc3RpbmcgY29udGFpbnMgdGhlIHJlbWFpbmluZyAyMCUuIEkgZXhwbG9yZWQgZm91ciBkaXN0aW5jdCBtb2RlbGluZyB0ZWNobmlxdWVzIHVzaW5nIGNyb3NzLXZhbGlkYXRpb24gdG8gYW5hbHl6ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gc2Vpc21pYyBtYWduaXR1ZGUgYW5kIG1heGltdW0gZGlzdGFuY2UgZnJvbSBwbGF0ZSBib3VuZGFyeS4gVGhlIGNvcnJlc3BvbmRpbmcgY29kZSBjYW4gYmUgZm91bmQgaW4gdGhlIGFwcGVuZGl4LgoKMS4gUmFuZG9tIEZvcmVzdDogUmFuZG9tIEZvcmVzdCBpcyBhbiBlbnNlbWJsZSB0cmVlLWJhc2VkIG1ldGhvZCB0aGF0IGNvbnN0cnVjdHMgbXVsdGlwbGUgZGVjaXNpb24gdHJlZXMgYW5kIG91dHB1dHMgdGhlIG1lYW4gcHJlZGljdGlvbiBvZiB0aGUgaW5kaXZpZHVhbCB0cmVlcyAoSmFtZXMsIFdpdHRlbiwgSGFzdGllLCAmIFRpYnNoaXJhbmksIDIwMjMpLgoKMi4gR3JhZGllbnQgQm9vc3RpbmcgTWFjaGluZSAoR0JNKTogR0JNIGlzIGEgYm9vc3RpbmcgYWxnb3JpdGhtIHRoYXQgaXMgYWxzbyBhIHRyZWUtYmFzZWQgbWV0aG9kLiBJdCBidWlsZHMgbXVsdGlwbGUgZGVjaXNpb24gdHJlZXMgd2l0aCBlYWNoIHRyZWUgdHJ5aW5nIHRvIGNvcnJlY3QgdGhlIGVycm9yIGZyb20gdGhlIHByZXZpb3VzIG9uZSAoSmFtZXMsIFdpdHRlbiwgSGFzdGllLCAmIFRpYnNoaXJhbmksIDIwMjMpLgoKMy4gUmVjdXJzaXZlIFBhcnRpdGlvbmluZyBUcmVlIChSUFQpOiBSUFQgaXMgYWxzbyBhIHRyZWUtYmFzZWQgbWV0aG9kLiBJdCBpcyBhIG5vbi1saW5lYXIgcHJlZGljdGl2ZSBtb2RlbCB0aGF0IGRpdmlkZXMgdGhlIGRhdGFzZXQgaW50byBzdWJzZXRzIGJhc2VkIG9uIHRoZSB2YWx1ZXMgb2YgdGhlIGlucHV0IHZhcmlhYmxlcyAoSXplbm1hbiwgMjAxMykuCgo0LiBMaW5lYXIgUmVncmVzc2lvbjogQSBzdXBlcnZpc2VkIGxlYXJuaW5nIG1vZGVsIHRoYXQgaXMgdXNlZCB0byBtb2RlbCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIGFuIGluZGVwZW5kZW50IHZhcmlhYmxlIChKYW1lcywgV2l0dGVuLCBIYXN0aWUsICYgVGlic2hpcmFuaSwgMjAyMykuCgpGb3IgYWxsIG1vZGVsaW5nIHRlY2huaXF1ZXMsIHRoZSBtYWduaXR1ZGUgd2FzIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIHRoZSBtYXhpbXVtIGRpc3RhbmNlIHdhcyB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgYW5kIHRoZXkgd2VyZSB0cmFpbmVkIG9uIHRoZSB0cmFpbmluZyBzZXQuIAoKCgpgYGB7ciBtb2RlbH0KIyBTcGxpdHRpbmcgdGhlIGRhdGEgaW50byB0cmFpbmluZyBhbmQgdGVzdGluZwpsaWJyYXJ5KGNhcmV0KQpzZXQuc2VlZCgxMjMpCnRyYWluX2luZGV4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZGYkbWFnLCBwID0gMC44LCBsaXN0ID0gRkFMU0UsIHRpbWVzID0gMSkKdHJhaW5fZGF0YSA8LSBkZlt0cmFpbl9pbmRleCwgXQp0ZXN0X2RhdGEgPC0gZGZbLXRyYWluX2luZGV4LCBdCgojIFRyYWluaW5nIHNldCB3aXRoIGEgcmVwZWF0ZWQgY3Jvc3MgdmFsaWRhdGlvbgp0cmFpbl9jdHJsIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAicmVwZWF0ZWRjdiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBudW1iZXIgPSA1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwZWF0cyA9IDMpCgpzZXQuc2VlZCgyMDE4KQoKIyBSZWN1cnNpdmUgUGFydGl0aW9uaW5nIFRyZWUgd2l0aCBvbmx5IGRpc3RhbmNlIGFzIGFuIGF0dHJpYnV0ZQpycGFydF90cmVlX2Rpc3QgPC0gdHJhaW4obWFnIH4gbWF4X2Rpc3RhbmNlLAogICAgICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9kYXRhLAogICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJycGFydCIsCiAgICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5fY3RybCkKCiMgUmFuZG9tIEZvcmVzdCBUcmVlIHdpdGggb25seSBEaXN0YW5jZSBhcyBhbiBhdHRyaWJ1dGUKcmZfdHJlZV9kaXN0IDwtIHRyYWluKG1hZyB+IG1heF9kaXN0YW5jZSwKICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fZGF0YSwKICAgICAgICAgICAgICAgICBtZXRob2QgPSAicmYiLAogICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluX2N0cmwpCgojIEdyYWRpZW50IEJvb3N0aW5nIE1hY2hpbmUgd2l0aCBvbmx5IGRpc3RhbmNlIGFzIGFuIGF0dHJpYnV0ZQpnYm1fdHJlZV9kaXN0IDwtIHRyYWluKG1hZyB+IG1heF9kaXN0YW5jZSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX2RhdGEsCiAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnYm0iLAogICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbl9jdHJsLAogICAgICAgICAgICAgICAgICBkaXN0cmlidXRpb24gPSAiZ2F1c3NpYW4iLAogICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpCgpsbV90cmVlX2Rpc3QgPC0gdHJhaW4obWFnIH4gbWF4X2Rpc3RhbmNlLAogICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fZGF0YSwKICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwKICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5fY3RybCkKCnJlc2FtcCA8LSByZXNhbXBsZXMobGlzdCgKICBycGFydF90cmVlID0gcnBhcnRfdHJlZV9kaXN0LCAKICByYW5kb21Gb3Jlc3QgPSByZl90cmVlX2Rpc3QsCiAgR0JNID0gZ2JtX3RyZWVfZGlzdCwKICBMTSA9IGxtX3RyZWVfZGlzdAopKQoKc3VtbWFyeShyZXNhbXApCmBgYAoKCiMjIyBSZXN1bHRzCgpUaGUgdmlzdWFsaXphdGlvbiBiZWxvdyBpbGx1c3RyYXRlcyB0aGUgcmVzdWx0cyBmcm9tIHRoZSBmb3VyIHRyYWluZWQgbW9kZWxzIHRoYXQgd2VyZSBtZW50aW9uZWQgaW4gdGhlIG1vZGVsaW5nIHNlY3Rpb24uIFRoZSBmaWd1cmUgc2hvd3MgdGhlIGJveCBwbG90cyBvZiB0aHJlZSBkaWZmZXJlbnQgdmFsdWVzLiBUaGUgZmlyc3QgYm94IHBsb3QgcmVwcmVzZW50cyB0aGUgTWVhbiBBYnNvbHV0ZSBFcnJvciAoTUFFKSBvZiB0aGUgbW9kZWxzLiBUaGUgTUFFIG1lYXN1cmVzIHRoZSBhYnNvbHV0ZSBhdmVyYWdlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgcHJlZGljdGl2ZSB2YWx1ZSBhbmQgdGhlIGFjdHVhbCB2YWx1ZS4gQSBsb3dlciBNQUUgaW5kaWNhdGVzIGEgYmV0dGVyIG1vZGVsLiBUaGUgc2Vjb25kIGJveCBwbG90IHJlcHJlc2VudHMgdGhlIFJvb3QgTWVhbiBTcXVhcmVkIEVycm9yIChSTVNFKS4gVGhlIFJNU0UgbWVhc3VyZXMgdGhlIHNxdWFyZSByb290IGF2ZXJhZ2UgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBwcmVkaWN0aXZlIHZhbHVlIGFuZCB0aGUgYWN0dWFsIHZhbHVlLiBJdCBpcyB2ZXJ5IHNpbWlsYXIgdG8gTUFFLCB3aXRoIGEgbG93ZXIgdmFsdWUgaW5kaWNhdGluZyBhIGJldHRlciBtb2RlbDsgaG93ZXZlciwgdGhlIFJNU0UgaXMgbW9yZSBzZW5zaXRpdmUgdG8gbGFyZ2VyIGVycm9ycyBhbmQgdGVuZHMgdG8gYmUgbW9yZSBhY2N1cmF0ZS4gVGhlIHRoaXJkIGJveCBwbG90IHJlcHJlc2VudHMgdGhlIFwoUl4yXCkgdmFsdWVzLiBUaGUgXChSXjJcKSBtZWFzdXJlcyBob3cgd2VsbCB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgY2FuIGV4cGxhaW4gdGhlIGRlcGVuZGVudCB2YXJpYWJsZS4gVGhlIHZhbHVlIHJhbmdlcyBmcm9tIDAgdG8gMSB3aGVyZSB0aGUgY2xvc2VyIHRoZSB2YWx1ZSBpcyB0byAxLCB0aGUgYmV0dGVyIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZSBjYW4gZXhwbGFpbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLiAKCgpgYGB7ciBib3hwbG90IHJlc3VsdHN9CiMgRXh0cmFjdCB2YWx1ZXMgZnJvbSByZXNhbXAgb2JqZWN0CnJlc2FtcF92YWx1ZXMgPC0gcmVzYW1wJHZhbHVlcwoKIyBSZXNoYXBlIHRoZSBkYXRhIHRvIGxvbmcgZm9ybWF0CnJlc2FtcF9sb25nIDwtIHBpdm90X2xvbmdlcihyZXNhbXBfdmFsdWVzLCBjb2xzID0gLVJlc2FtcGxlLCBuYW1lc190byA9ICJNb2RlbF9NZXRyaWMiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKQoKIyBFeHRyYWN0IG1vZGVscyBhbmQgbWV0cmljcyBmcm9tIHRoZSBNb2RlbF9NZXRyaWMgY29sdW1uCnJlc2FtcF9sb25nIDwtIHNlcGFyYXRlKHJlc2FtcF9sb25nLCBjb2wgPSBNb2RlbF9NZXRyaWMsIGludG8gPSBjKCJNb2RlbCIsICJNZXRyaWMiKSwgc2VwID0gIn4iKQoKcmVzYW1wX2xvbmckTW9kZWwgPC0gZmFjdG9yKHJlc2FtcF9sb25nJE1vZGVsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInJhbmRvbUZvcmVzdCIsICJycGFydF90cmVlIiwgIkdCTSIsICJMTSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiUmFuZG9tIEZvcmVzdCIsICJSUFQiLCAiR0JNIiwgIkxpbmVhciBSZWdyZXNzaW9uIikpCgpjdXN0b21fcGFsZXR0ZSA8LSBjKCIjMDA3MkIyIiwgIiNENTVFMDAiLCAiIzAwOUU3MyIsICIjQ0M3OUE3IikKCiMgQ3JlYXRpbmcgYSB0aGVtZQpjdXN0b21fdGhlbWUgPC0gdGhlbWVfaXBzdW0oYmFzZV9zaXplID0gMTIpICsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmV5ODAiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkgCiAgKQoKZ2dwbG90KGRhdGEgPSByZXNhbXBfbG9uZywgYWVzKHggPSBNb2RlbCwgeSA9IFZhbHVlLCBmaWxsID0gTW9kZWwpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgd2lkdGggPSAwLjYpICsKICBmYWNldF93cmFwKH4gTWV0cmljLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9wYWxldHRlKSArCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90IG9mIE1ldHJpY3MgYnkgTW9kZWwiLAogICAgICAgeCA9ICJNb2RlbCIsCiAgICAgICB5ID0gIlZhbHVlIiwKICAgICAgIGZpbGwgPSAiTW9kZWwiKSArCiAgY3VzdG9tX3RoZW1lCgoKYGBgCgpBcyBwcmV2aW91c2x5IGRpc2N1c3NlZCwgbG93ZXIgTUFFIGFuZCBSTVNFIHZhbHVlcywgYWxvbmcgd2l0aCBhIGhpZ2ggdmFsdWUgb2YgdGhlIFIyIGluZGljYXRlcyBhIGJldHRlciBtb2RlbCBwZXJmb3JtYW5jZS4gVGhlcmVmb3JlLCB0aGUgb2JqZWN0aXZlIGlzIHRvIGlkZW50aWZ5IHRoZSBtb2RlbCB0aGF0IHNob3dzIHRoZSBiZXN0IHJlc3VsdHMuIFVwb24gaW5pdGlhbCBpbnNwZWN0aW9uLCB0aGUgUmFuZG9tIEZvcmVzdCBtb2RlbCBvdXRwZXJmb3JtZWQgdGhlIG90aGVyIG1vZGVscyBhY3Jvc3MgYWxsIHNjYWxlcy4gVGhlIE1BRSBhbmQgUk1TRSB2YWx1ZXMgc3VnZ2VzdCB0aGF0IHRoZSBwcmVkaWN0aW9ucyB3ZXJlIGdlbmVyYWxseSBhY2N1cmF0ZSB3aXRoIGxpdHRsZSB0byBub25lIHZhcmlhdGlvbi4gVGhlIFwoUl4yXCkgdmFsdWUgb2YgMC45OTk2IHNob3dzIHRoYXQgdGhlIG1vZGVsIGV4cGxhaW5lZCB0aGUgbWFqb3JpdHkgb2YgdGhlIHZhcmlhbmNlIGluIHRoZSBkYXRhLiBPdmVyYWxsLCB0aGVzZSByZXN1bHRzIGluZGljYXRlIHRoYXQgdGhlIG1vZGVsIGNhcHR1cmVkIHBhdHRlcm5zIGluIHRoZSBkYXRhIGFuZCBpdCBpcyBoaWdobHkgYWNjdXJhdGUgYW5kIHJlbGlhYmxlLiAKCgoKYGBge3J9CiMgTWFraW5nIHByZWRpY3Rpb25zIHVzaW5nIHJhbmRvbUZvcmVzdCBtb2RlbApwcmVkaWN0aW9uc19yZiA8LSBwcmVkaWN0KHJmX3RyZWVfZGlzdCwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkKCmNhdCgiUmFuZG9tIEZvcmVzdCBQcmVkaWN0aW9uOiIsIG1lYW4ocHJlZGljdGlvbnNfcmYpLCAiXG4iKQpgYGAKClRoZSB0cmFpbmVkIHJhbmRvbSBmb3Jlc3QgbW9kZWwgd2FzIHVzZWQgdG8gbWFrZSBwcmVkaWN0aW9ucyBvbiB0aGUgdGVzdGluZyBkYXRhc2V0LCByZXN1bHRpbmcgaW4gYSBwcmVkaWN0ZWQgc2Vpc21pYyBtYWduaXR1ZGUgb2YgNC43NTUuIFRoaXMgcHJlZGljdGlvbiBleHBsYWlucyB0aGUgbW9kZWzigJlzIGFiaWxpdHkgdG8gZXN0aW1hdGUgdGhlIG1hZ25pdHVkZSBiYXNlZCBvbiB0aGUgbWF4aW11bSBwbGF0ZSBwcm94aW1pdHkuIE5vdGFibHksIHRoZSBtZWFuIG9mIHRoZSBtYWduaXR1ZGUgaW4gdGhlIGRhdGFzZXQgaXMgNC43NSB3aGljaCBpbmRpY2F0ZXMgdGhhdCB0aGUgcHJlZGljdGVkIHZhbHVlIGFsaWducyBjbG9zZWx5IHdpdGggdGhlIGF2ZXJhZ2UgbWFnbml0dWRlIG9ic2VydmVkIGluIHRoZSBkYXRhc2V0LgoKCiMjICoqQ29uY2x1c2lvbioqIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzIH0KClRoZSBzY2llbmNlIG9mIHNlaXNtb2xvZ3kgaXMgZGF0ZWQgYmFjayB0byB0aGUgbGF0ZSBuaW5ldGVlbnRoIGNlbnR1cnkgYW5kIHNjaWVudGlzdHMgaGF2ZSBmb3VuZCB2YWx1YWJsZSBpbnNpZ2h0cyBpbiB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBzZWlzbWljIGFjdGl2aXR5IGFuZCBwbGF0ZSB0ZWN0b25pY3MuIE92ZXIgdGhlIHllYXJzLCB0aGV5IGhhdmUgbGlua2VkIHRoZSBkZXB0aCBvZiBhIHNlaXNtaWMgZXZlbnQgd2l0aCB0aGUgc2Vpc21pYyBtYWduaXR1ZGUuIEFzIHdlbGwgYXMgdGhlIGRpZmZlcmVudCBlZmZlY3RzIGFuZCBjaGFyYWN0ZXJpc3RpY3MgYmV0d2VlbiBib3VuZGFyeSB0eXBlcy4gSW4gdGhpcyBzdHVkeSwgSSBpbnZlc3RpZ2F0ZWQgdGhlIGltcGFjdCBvZiBwbGF0ZSBwcm94aW1pdHkgb24gc2Vpc21pYyBtYWduaXR1ZGUgdXNpbmcgYSBkYXRhc2V0IG9mIGFwcHJveGltYXRlbHkgOCw2MDAgcmVjb3JkZWQgc2Vpc21pYyBldmVudHMgZnJvbSB0aGUgeWVhciAyMDIzLiBXaXRoIHRoZSBoZWxwIG9mICB0aGUgSGF2ZXJzaW5lIGZvcm11bGEsIEkgY3JlYXRlZCBhbiBhZGRpdGlvbmFsIGF0dHJpYnV0ZSByZXByZXNlbnRpbmcgdGhlIGRpc3RhbmNlIGJldHdlZW4gZWFjaCBzZWlzbWljIGV2ZW50IGFuZCB0aGUgbmVhcmVzdCB0ZWN0b25pYyBwbGF0ZS4gCgpCeSBjb21iaW5pbmcgdmFyaW91cyB2aXN1YWxpemF0aW9ucywgSSB1bmRlcnN0b29kIHRoZSBiZWhhdmlvciBhbmQgcmVsYXRpb25zaGlwIGJldHdlZW4gc2Vpc21pYyBtYWduaXR1ZGUgYW5kIHBsYXRlIHByb3hpbWl0eS4gQnkgaW1wbGVtZW50aW5nIHRoZSBFeHRyZW1lIHZhbHVlIHRoZW9yZW0sIEkgdW5jb3ZlcmVkIGEgcGF0dGVybiBpbmRpY2F0aW5nIGEgZ3JlYXRlciBwbGF0ZSBwcm94aW1pdHkgaGFzIGNvcnJlbGF0aW9uIHdpdGggbG93ZXIgc2Vpc21pYyBtYWduaXR1ZGUgd2l0aGluIHRoZSBkYXRhc2V0LiBVdGlsaXppbmcgdGhpcyBwYXR0ZXJuLCBJIHRyYWluZWQgYSBSYW5kb20gRm9yZXN0IG1vZGVsIHRvIHByZWRpY3QgdGhlIG1hZ25pdHVkZSBvZiBhIHNlaXNtaWMgZXZlbnQgd2l0aCB0aGUgbWF4aW11bSBkaXN0YW5jZSBmcm9tIGEgdGVjdG9uaWMgcGxhdGUuIEZpbmFsbHksIEkgdXNlZCB0aGUgdHJhaW5lZCBtb2RlbCB0byBtYWtlIHByZWRpY3Rpb25zIG9uIHRoZSB1bnRyYWluZWQgcGFydCBvZiB0aGUgZGF0YXNldCwgd2l0aCBhY2N1cmF0ZSBhbmQgcmVsaWFibGUgcmVzdWx0cy4gCgoKIyMgKipSZWZlcmVuY2VzKiogey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHMgfQoKQWduZXcgRC4gQy4gKDE5ODksIEphbnVhcnkgMSkuIFNlaXNtb2xvZ3kgSGlzdG9yeS4gU3ByaW5nZXIgTGluay4gPGh0dHBzOi8vbGluay5zcHJpbmdlci5jb20vcmVmZXJlbmNld29ya2VudHJ5LzEwLjEwMDcvMC0zODctMzA3NTItNF8xNDM+IAoKQXQgd2hhdCBkZXB0aCBkbyBlYXJ0aHF1YWtlcyBvY2N1cj8gV2hhdCBpcyB0aGUgc2lnbmlmaWNhbmNlIG9mIHRoZSBkZXB0aD8uIChuLmQuKS4gVVNHUy4gUmV0cmlldmVkIEFwcmlsIDI3LCAyMDI0LCBmcm9tIDxodHRwczovL3d3dy51c2dzLmdvdi9mYXFzL3doYXQtZGVwdGgtZG8tZWFydGhxdWFrZXMtb2NjdXItd2hhdC1zaWduaWZpY2FuY2UtZGVwdGg+CgpJemVubWFuLCBBLkouICgyMDEzKS4gUmVjdXJzaXZlIFBhcnRpdGlvbmluZyBhbmQgVHJlZS1CYXNlZCBNZXRob2RzLiBJbjogTW9kZXJuIE11bHRpdmFyaWF0ZSBTdGF0aXN0aWNhbCBUZWNobmlxdWVzLiBTcHJpbmdlciBUZXh0cyBpbiBTdGF0aXN0aWNzLiBTcHJpbmdlciwgTmV3IFlvcmssIE5ZLiA8aHR0cHM6Ly9kb2kub3JnLzEwLjEwMDcvOTc4LTAtMzg3LTc4MTg5LTFfOT4KCkphbWVzLCBHLiwgV2l0dGVuLCBELiwgSGFzdGllLCBULiAmIFRpYnNoaXJhbmksIFIuICgyMDIzKS4gQW4gSW50cm9kdWN0aW9uIHRvIFN0YXRpc3RpY2FsIExlYXJuaW5nOiB3aXRoIEFwcGxpY2F0aW9ucyBpbiBSOiBTZWNvbmQgRWRpdGlvbi4gCgpLZXNlciwgTS4gKDIwMjMsIERlY2VtYmVyIDMwKS4gRWFydGhxdWFrZXMgMjAyMyBHbG9iYWwuIEthZ2dsZS4gUmV0cmlldmVkIEphbnVhcnkgMzAsIDIwMjQsIGZyb20gPGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvbXVzdGFmYWtlc2VyNC9lYXJ0aHF1YWtlcy0yMDIzLWdsb2JhbD4KCk5hdGlvbmFsIEdlb2dyYXBoaWMgU29jaWV0eS4gKDIwMjQsIE1hcmNoIDcpLiBQbGF0ZSBCb3VuZGFyaWVzLiBOYXRpb25hbCBHZW9ncmFwaGljLiA8aHR0cHM6Ly9lZHVjYXRpb24ubmF0aW9uYWxnZW9ncmFwaGljLm9yZy9yZXNvdXJjZS9wbGF0ZS1ib3VuZGFyaWVzLz4KClRob21wc29uLCBDLiAoMjAyMCwgTWF5IDEzKS4gVGVjdG9uaWMgUGxhdGUgQm91bmRhcmllcy4gS2FnZ2xlLiBSZXRyaWV2ZWQgTWFyY2ggMjYsIDIwMjQsIGZyb20gPGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvY3d0aG9tcHNvbi90ZWN0b25pYy1wbGF0ZS1ib3VuZGFyaWVzL2RhdGE+CgpVcGFkaHlheSwgQS4gKDIwMjQsIEphbnVhcnkgMjEpLiBIYXZlcnNpbmUgZm9ybXVsYSAtIENhbGN1bGF0ZSBnZW9ncmFwaGljIGRpc3RhbmNlIG9uIGVhcnRoLiBJZ2lzbWFwLiA8aHR0cHM6Ly93d3cuaWdpc21hcC5jb20vaGF2ZXJzaW5lLWZvcm11bGEtY2FsY3VsYXRlLWdlb2dyYXBoaWMtZGlzdGFuY2UtZWFydGgvPgoKVmlrdWxlZyBKYXLDsHNrasOhbGZ0YXlmaXJsaXQuIChuLmQuKS4gVmXDsHVyc3RvZmEgw41zbGFuZHMuIFJldHJpZXZlZCBBcHJpbCAyNywgMjAyNCwgZnJvbSA8aHR0cHM6Ly93d3cudmVkdXIuaXMvc2tqYWxmdGFyLW9nLWVsZGdvcy95ZmlybGl0L21hbnVkaXIvamFyZHNramFsZnRheWZpcmxpdC00NS12aWt1LTA3LTE0LW5vdmVtYmVyLTIwMjM+CgpXaWxzb24sIE0uICgyMDIxLCBKdW5lIDcpLiA1LjMgRWFydGhxdWFrZXMgYW5kIFBsYXRlIFRlY3Rvbmljcy4gTWFyaWNvcGEuCjxodHRwczovL29wZW4ubWFyaWNvcGEuZWR1L2hhemFyZHMvY2hhcHRlci9lYXJ0aHF1YWtlcy1hbmQtcGxhdGUtdGVjdG9uaWNzLz4KCgoK