Survival Analysis and Kaplan-Meier Curves

Introduction and Background

The year 2020 shall go down in history as a year in which a highly contagious and never-before-seen coronavirus spread across the world with devastating consequences. For the many who were unfortunate enough to contract this potentially deadly virus (now and in the future), likely one of the most important questions on their minds was whether or not they will be OK. However, if an infected patient were to ask their doctor this question, it's highly likely that the answer provided was not a definitive Yes or No. It may have been a "It should be all right," or "I expect things to improve," or possibly even "we're doing the best we can." To the patient, this non-binary sort-of-an-answer might be frustrating to hear, but it really is likely the best possible answer that can be given at the time. This is because biology (and biologic processes, in general) are predominantly stochastic in nature. In other words, they are not deterministic. This kind of non-deterministic behavior is certainly not unique to medicine and biology, but rather arises in many aspects of the world we live in. What's more, depending on the circumstances, different styles of mathematical analysis may be necessary in order to understand or characterize the behavior of the scenario at hand. In the realm of medicine and engineering, arguably the most common method of approach for these kinds of problems is survival analysis, alternatively known as time-to-failure analysis.

What is Survival Analysis and how does it work? At its core, survival analysis is a sub-branch of Statistics that is used for analyzing the amount of time that passes before an event occurs. When applied to biological organisms, as in medical applications, this event is often death (though not always). For non-biological systems (i.e. mechanical systems), this event is often some kind of mechanical failure. The underlying principle behind this field of analysis is the assumption of a fundamental conditional function that relates the probability that a given patient/device/object will survive without experiencing an event past a given amount of time. This fundamental function, or relationship, is referred to as the survival function. While there are a number of statistical arguments justifying the fundamental existence of these survival functions (and their appropriateness in describing these kinds of phenomena), I will refrain from delving into this topic. There are several methods/models that are used to estimate the survival function of time-to-event data; in this document, I will focus exclusively on one of the more common techniques, and explain in detail how it works, why it has such widespread acclaim, and some of the limitations that are inherent in its use.

The Kaplan-Meier Estimator

The Kaplan-Meier Estimator emerged from the groundbreaking paper on Nonparametric Estimation From Incomplete Observations by Edward Kaplan and Paul Meier in 1958 (link). In terms of impact, this paper is one of the most cited scientific papers of all time, and was ranked 11th in 2014 with approximately 38,600 citations, according to an article published in the journal Nature (link). The formula that was proposed in this groundbreaking paper (and later named after the two authors) suggested that the Survival function \(S(t)\) could be non-parametrically estimated in the following way:

\[ \begin{array}{rcl} \hat{S}(t) &=& \displaystyle \prod_{i:\ t_i\le t}\bigg(1-\frac{d_i}{n_i}\bigg) \end{array} \]

Where \(t_i\) is a time in which at least one event occurred, \(d_i\) is the number of events that occurred at \(t_i\), and \(n_i\) is the number of objects of interest that have been known to have not had an event (i.e. survived) up to \(t_i\). As evident from the formula, this is an example of a non-parametric statistic. To best get a feel for how this formula works, it is useful to examine this formula in the context of a simple example.

ID Time Event
ID1 1 1
ID2 2 1
ID3 3 1
ID4 4 1
ID5 5 1

In this simple example, there are five participants/objects in the study. The time-to-event duration of ID1 was 1 (unit of time). For ID2, it was 2, and so on. From this time-to-event data, we can calculate \(n_i\) and \(d_i\) is a very simple fashion. From these inputs, the Kaplan-Meier estimator is determined to be the following:

Notice that at each step in above graphic, the survival function dropped by an amount that was equal to the current survival function value multiplied by \(d_i/n_i\). At \(t=1\), \(n_i=5\), \(d_i=1\) and \(\hat{S}(t)=1\), and thus the function dropped by \(1\times 1/5 = 0.2\). At \(t=2\), \(n_i=4\), \(d_i=1\) and \(\hat{S}(t)=0.8\), and thus the function dropped by \(0.8\times 1/4 = 0.2\). At \(t=3\), the function dropped by \(0.6\times 1/3 = 0.2\). And so on. Take a moment to go back to the formula and verify that this behavior is indeed reflected by the provided formulation.

The insight to be gained from this is the fact that the survival function counts all participants who have survived up until a given time/duration \(t\) (as opposed to only those participants at or around time \(t\)), only needs to be calculated for the points in which there was an event (because whenever there are no events, the survival function drops by \(\hat{S}(t)\times 0/n_i = 0\) and thus can be completely ignored), it is cumulative (ensuring that all data points can have an effect on the estimated result, suggesting that the information that is available in the data is used effectively), and it is quite easy to calculate.

Why does this product of ratios provide accurate estimates of the survival probability larger than some given duration of time? The simplest explanation of this can be described from the perspective of conditional probability. Suppose that you are trying to find \(\hat{S}(3) = \mathsf{P}(T > 3)\), where \(T\) is the true/unknown time-to-death of the object of interest. By using conditional probability, we can expand this out in the following way.
\[ \begin{array}{rcll} \hat{S}(3) &=& \mathsf{P}(T > 3) \\ &=& \mathsf{P}(T > 3\ \cap \ T>2) & \text{Since }\ \mathsf{P}(T > 3) = \mathsf{P}(T > 3 \ \cap \ T>2) \\ &=& \mathsf{P}(T > 3\ |\ T>2) \times \mathsf{P}(T>2) & \text{Bayes Theorem} \\ &=& \mathsf{P}(T > 3\ |\ T>2) \times \mathsf{P}(T>2\ |\ T>1.5) \times \mathsf{P}(T>1.5) & ... \end{array} \]

The fact that the survival probability at 3 years of age can be written to be proportional to that at 2 years of age can be understood as reflecting the fact that the object can only survive 3 years of age after first surviving 2 years of age. One can then repeat this argument as much as necessary to obtain the desired extended product as the result. With this in mind, the original formula should make a lot more sense.

With this introductory example out of the way, we can dive a little deeper into the nuances of this formulation, as well as the reasons why it is one of the most popular approaches to survival analysis. Let's start with the primary problem that Kaplan and Meier built this estimator to combat; namely missing and incomplete time-to-event data.

For any kind of time-to-event scenario, there are always a number of options that a given patient/object-of-interest may be characterized by at a given moment in time (as relevant to the analysis):

  1. The event has happened, and the time-to-event duration is known (complete data)
  2. The event has not happened (yet), and the duration of time without an event is known (right-censored data)
  3. The event has not happened and never will happen due to removal or lack of communication/knowledge, and the known/confirmed duration of time without an event (i.e. time-to-last communication/knowledge) is known (right-censored data)

NOTE: Other possible options, such as interval censoring, are not considered here.

The power behind the Kaplan-Meier Estimator is that unlike other more naive survival function estimation approaches, which may only be able to reliable extract information from data sources/records that are 'complete', the Kaplan Meier estimator can be proven to be able to effectively make use of both complete and right-censored data to craft the estimated survival function. Specifically, this ensures that none of the data is thrown out due to the incompleteness of the data observations. This, in combination with its status as a non-parametric estimator, is arguably the reason behind its' profound popularity in practical applications (particularly medicine research), as more likely than not you will never have time-to-event datasets that are complete (in the sense that all records are complete). As a simple, but profound, example, suppose you want to better understand human lifetimes (i.e. time-to-death). If you don't throw out any potential data, you will never have a complete dataset of time-to-death data, simply because you yourself are still alive (and thus your time-to-death duration is not known). Waiting until such a time that one has complete data in this case (and in many others) is thus completely ridiculous. Rather, if the approach being used truly does require nothing but complete data, then all the data records with incomplete information would need to be removed from consideration, reducing the size of the data sample and, as a consequence, the accuracy of the final result. However, with the Kaplan-Meier Estimator, this is not an issue, as it was specifically formulated in such a way that even incomplete data records can be effectively made use of.

In fact, with respect to the estimated survival function using the Kaplan-Meier Estimator, none of these censored data records actually cause the survival curve to drop, as we have previously demonstrated that the only 'drops' in the survival curve occur when there are a non-zero number of 'events' at some time/duration \(t_i\). However, they do still play a role in the overall calculation by affecting the value of \(n_i\), or the number of objects of interest that have been observed to have survived without an event for a duration longer than \(t_i\). This is because, while the true time-to-event duration of these censored objects may not be known, it is known that they must be larger than the current age of the objects. As a demonstration of the effect of these censored data records, if we modify our original simple example such that the ID3 is no longer an 'event', but rather a right-censored data point, then the result is as follows:

ID Time Event
ID1 1 1
ID2 2 1
ID3 3 0
ID4 4 1
ID5 5 1

Here, the right-censored data record is specified by ensuring the value in the Event column associated with this record (namely ID3) is zero.

There are a few things to note here. First, at \(t=3\), there was no drop in the Kaplan-Meier survival function estimate. This is because there were no events at \(t=3\) (i.e. when \(t_i=3\), \(d_i=0\), as can be seen in the sub-graph for \(d_i\)). Second, there is no change in the graph of \(n_i\) for this slightly modified sample dataset. Third, the reduction in the survival function was larger at \(t=4\) than it was at \(t=2\). Specifically, when \(t_i=4\), the survival function at this time was \(\hat{S}(t)=0.6\), with \(d_i=1\) and \(n_i=2\). Plugging in, we find that the overall size of the drop should be equal to \(0.6\times1/2=0.3\). It's important to note that the information provided by the censored data record behaved exactly like the previous version (in which all time-to-event measurements were known) up to the point where no further information was known regarding the time-to-event of the given record (i.e. it is know to be larger than 3, but nothing more than that). At the same time, no assumptions regarding the true time-to-event duration are made, which is why the curve differed slightly after \(t=3\) compared to the original version (because of this incomplete/unknown information). This demonstrates how useful information can be extracted even from incomplete data records using the Kaplan-Meier Estimator in such a way that no implicit assumptions regarding unknown information are made.

Practical Considerations

In addition to all that we have discussed up to this point, there are also a number of practical considerations that one should be aware of when using and applying the Kaplan-Meier Estimator to time-to-event data. The first that, like all mathematical models, the sample size and quality of the data matter. To be more mathematically precise, the confidence of the resulting curve fit will depend on the data that is used. It is standard practice to use a 95% confidence level when constructing confidence intervals for the estimated fit. The exact details regarding how these confidence intervals are constructed lie outside the scope of this document; however, at a high-level, larger datasets with few censored data records have the tightest confidence intervals (i.e. low uncertainty), while small datasets with many censored data records have the largest confidence intervals (i.e. high uncertainty). This is demonstrated in the example below, using time-to-event survival data drawn from a Geometric distribution and censoring determined by a Binomial distribution with probability \(p\).

\[ \begin{array}{rcl} T\sim \text{Geom}(0.05) && E_{vent} \sim B(1, p) \end{array} \]

Conclusion

Just as any other mathematical model, there are pros and cons associated with using the Kaplan-Meier Estimator to estimate the survival function of some phenomenon of interest. The fact that it is a non-parametric approach to estimating the survival function is something that makes it particularly desirable in many cases for a number of reasons. As a non-parametric estimator, it makes very few implicit assumptions regarding the phenomenon of interest, and thus may be used for a wide range of time-to-event applications. Performance-wise, it is also quite robust and is unbiased, at least up to the last observed event in the provided data (note that this may not be the maximum observed duration in the data if the records with the largest duration are censored). As an additional perk, the Kaplan-Meier Estimator can be demonstrated to be the Maximum-Likelihood Estimator for these kinds of time-to-event analyses (specifically, it is the MLE of the Hazard Function).

Despite all this, the Kaplan-Meier Estimator may not always be the optimal choice for a given time-to-event application. For example, there are many applications in the world of engineering in which enough is known about the problem at hand such that parametric approaches to this kind of survival analysis are not only possible, but also have better performance compared to their non-parametric counterparts. Of particularly note in this respect is the improvement in statistical 'Power' that many parametric approaches provide even with the same input data. What's more, the Kaplan-Meier Estimator is not particular flexible with respect to adjusting for covariates that may affect the underlying survival function of interest. And lastly, the Kaplan-Meier Estimator is not able to account for censored data records that are not right-censored (e.g. left or interval-censored data).

In conclusion, the Kaplan-Meier estimate is a powerful tool that can be used to develop an estimate of the survival function defining a specific process or phenomenon when dealing with time-to-event data. Being able to estimate the survival function is very useful and powerful, as it can be used for a wide range of applications, including predicting future performance (such as the mechanical failure rate of servers in a datacenter, or the maintenance needs of a number of assets in the next two years), or comparing the survival rates between different data sub-populations (such as the long-term performance of two different vaccines with respect to conferring immunity or resistance to a pathogen).

## R Session Information:
## R version 4.0.3 (2020-10-10)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19041)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252   
## [3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.1252    
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] survminer_0.4.8 ggpubr_0.4.0    survival_3.2-7  reshape2_1.4.4  gridExtra_2.3   dplyr_1.0.2    
## [7] plyr_1.8.6      ggplot2_3.3.2  
## 
## loaded via a namespace (and not attached):
##  [1] zoo_1.8-8         tidyselect_1.1.0  xfun_0.19         purrr_0.3.4       splines_4.0.3    
##  [6] haven_2.3.1       lattice_0.20-41   carData_3.0-4     colorspace_2.0-0  vctrs_0.3.5      
## [11] generics_0.1.0    htmltools_0.5.0   yaml_2.2.1        survMisc_0.5.5    rlang_0.4.9      
## [16] pillar_1.4.7      foreign_0.8-80    glue_1.4.2        withr_2.3.0       readxl_1.3.1     
## [21] lifecycle_0.2.0   stringr_1.4.0     cellranger_1.1.0  munsell_0.5.0     ggsignif_0.6.0   
## [26] gtable_0.3.0      zip_2.1.1         evaluate_0.14     labeling_0.4.2    knitr_1.30       
## [31] rio_0.5.16        rmdformats_1.0.0  forcats_0.5.0     curl_4.3          highr_0.8        
## [36] broom_0.7.2       Rcpp_1.0.5        xtable_1.8-4      scales_1.1.1      backports_1.2.0  
## [41] abind_1.4-5       km.ci_0.5-2       farver_2.0.3      hms_0.5.3         digest_0.6.27    
## [46] openxlsx_4.2.3    stringi_1.5.3     bookdown_0.21     rstatix_0.6.0     KMsurv_0.1-5     
## [51] tools_4.0.3       magrittr_2.0.1    tibble_3.0.4      crayon_1.3.4      tidyr_1.1.2      
## [56] car_3.0-10        pkgconfig_2.0.3   ellipsis_0.3.1    Matrix_1.2-18     data.table_1.13.2
## [61] rmarkdown_2.5     R6_2.5.0          compiler_4.0.3
LS0tDQp0aXRsZTogIlN1cnZpdmFsIEFuYWx5c2lzIGFuZCBLYXBsYW4tTWVpZXIgQ3VydmVzIg0KYXV0aG9yOiAiTWljaGFlbCBPJ0Nvbm5vciINCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDogDQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOg0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGhpZ2hsaWdodDogaGFkZG9jaw0KICAgIHRodW1ibmFpbHM6IGZhbHNlDQogICAgbGlnaHRib3g6IHllcw0KICBwZGZfZG9jdW1lbnQ6DQogICAgbGF0ZXhfZW5naW5lOiB4ZWxhdGV4DQp1cmxjb2xvcjogJ2JsdWUnDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IEZBTFNFLCBmaWcud2lkdGggPSA5LCBmaWcuaGVpZ2h0ID0gNC41KQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShwbHlyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ3JpZCkNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShyZXNoYXBlMikNCmBgYA0KDQoNCiMjIEludHJvZHVjdGlvbiBhbmQgQmFja2dyb3VuZA0KDQpUaGUgeWVhciAyMDIwIHNoYWxsIGdvIGRvd24gaW4gaGlzdG9yeSBhcyBhIHllYXIgaW4gd2hpY2ggYSBoaWdobHkgY29udGFnaW91cyBhbmQgbmV2ZXItYmVmb3JlLXNlZW4gY29yb25hdmlydXMgc3ByZWFkIGFjcm9zcyB0aGUgd29ybGQgd2l0aCBkZXZhc3RhdGluZyBjb25zZXF1ZW5jZXMuIEZvciB0aGUgbWFueSB3aG8gd2VyZSB1bmZvcnR1bmF0ZSBlbm91Z2ggdG8gY29udHJhY3QgdGhpcyBwb3RlbnRpYWxseSBkZWFkbHkgdmlydXMgKG5vdyBhbmQgaW4gdGhlIGZ1dHVyZSksIGxpa2VseSBvbmUgb2YgdGhlIG1vc3QgaW1wb3J0YW50IHF1ZXN0aW9ucyBvbiB0aGVpciBtaW5kcyB3YXMgd2hldGhlciBvciBub3QgdGhleSB3aWxsIGJlIE9LLiBIb3dldmVyLCBpZiBhbiBpbmZlY3RlZCBwYXRpZW50IHdlcmUgdG8gYXNrIHRoZWlyIGRvY3RvciB0aGlzIHF1ZXN0aW9uLCBpdCdzIGhpZ2hseSBsaWtlbHkgdGhhdCB0aGUgYW5zd2VyIHByb3ZpZGVkIHdhcyBub3QgYSBkZWZpbml0aXZlIFllcyBvciBOby4gSXQgbWF5IGhhdmUgYmVlbiBhICJJdCBzaG91bGQgYmUgYWxsIHJpZ2h0LCIgb3IgIkkgZXhwZWN0IHRoaW5ncyB0byBpbXByb3ZlLCIgb3IgcG9zc2libHkgZXZlbiAid2UncmUgZG9pbmcgdGhlIGJlc3Qgd2UgY2FuLiIgVG8gdGhlIHBhdGllbnQsIHRoaXMgbm9uLWJpbmFyeSBzb3J0LW9mLWFuLWFuc3dlciBtaWdodCBiZSBmcnVzdHJhdGluZyB0byBoZWFyLCBidXQgaXQgcmVhbGx5IGlzIGxpa2VseSB0aGUgYmVzdCBwb3NzaWJsZSBhbnN3ZXIgdGhhdCBjYW4gYmUgZ2l2ZW4gYXQgdGhlIHRpbWUuIFRoaXMgaXMgYmVjYXVzZSBiaW9sb2d5IChhbmQgYmlvbG9naWMgcHJvY2Vzc2VzLCBpbiBnZW5lcmFsKSBhcmUgcHJlZG9taW5hbnRseSBzdG9jaGFzdGljIGluIG5hdHVyZS4gSW4gb3RoZXIgd29yZHMsIHRoZXkgYXJlIG5vdCBkZXRlcm1pbmlzdGljLiBUaGlzIGtpbmQgb2Ygbm9uLWRldGVybWluaXN0aWMgYmVoYXZpb3IgaXMgY2VydGFpbmx5IG5vdCB1bmlxdWUgdG8gbWVkaWNpbmUgYW5kIGJpb2xvZ3ksIGJ1dCByYXRoZXIgYXJpc2VzIGluIG1hbnkgYXNwZWN0cyBvZiB0aGUgd29ybGQgd2UgbGl2ZSBpbi4gV2hhdCdzIG1vcmUsIGRlcGVuZGluZyBvbiB0aGUgY2lyY3Vtc3RhbmNlcywgZGlmZmVyZW50IHN0eWxlcyBvZiBtYXRoZW1hdGljYWwgYW5hbHlzaXMgbWF5IGJlIG5lY2Vzc2FyeSBpbiBvcmRlciB0byB1bmRlcnN0YW5kIG9yIGNoYXJhY3Rlcml6ZSB0aGUgYmVoYXZpb3Igb2YgdGhlIHNjZW5hcmlvIGF0IGhhbmQuIEluIHRoZSByZWFsbSBvZiBtZWRpY2luZSBhbmQgZW5naW5lZXJpbmcsIGFyZ3VhYmx5IHRoZSBtb3N0IGNvbW1vbiBtZXRob2Qgb2YgYXBwcm9hY2ggZm9yIHRoZXNlIGtpbmRzIG9mIHByb2JsZW1zIGlzIHN1cnZpdmFsIGFuYWx5c2lzLCBhbHRlcm5hdGl2ZWx5IGtub3duIGFzIHRpbWUtdG8tZmFpbHVyZSBhbmFseXNpcy4gDQoNCg0KV2hhdCBpcyBTdXJ2aXZhbCBBbmFseXNpcyBhbmQgaG93IGRvZXMgaXQgd29yaz8gQXQgaXRzIGNvcmUsIHN1cnZpdmFsIGFuYWx5c2lzIGlzIGEgc3ViLWJyYW5jaCBvZiBTdGF0aXN0aWNzIHRoYXQgaXMgdXNlZCBmb3IgYW5hbHl6aW5nIHRoZSBhbW91bnQgb2YgdGltZSB0aGF0IHBhc3NlcyBiZWZvcmUgYW4gZXZlbnQgb2NjdXJzLiBXaGVuIGFwcGxpZWQgdG8gYmlvbG9naWNhbCBvcmdhbmlzbXMsIGFzIGluIG1lZGljYWwgYXBwbGljYXRpb25zLCB0aGlzIGV2ZW50IGlzIG9mdGVuIGRlYXRoICh0aG91Z2ggbm90IGFsd2F5cykuIEZvciBub24tYmlvbG9naWNhbCBzeXN0ZW1zIChpLmUuIG1lY2hhbmljYWwgc3lzdGVtcyksIHRoaXMgZXZlbnQgaXMgb2Z0ZW4gc29tZSBraW5kIG9mIG1lY2hhbmljYWwgZmFpbHVyZS4gVGhlIHVuZGVybHlpbmcgcHJpbmNpcGxlIGJlaGluZCB0aGlzIGZpZWxkIG9mIGFuYWx5c2lzIGlzIHRoZSBhc3N1bXB0aW9uIG9mIGEgZnVuZGFtZW50YWwgY29uZGl0aW9uYWwgZnVuY3Rpb24gdGhhdCByZWxhdGVzIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGEgZ2l2ZW4gcGF0aWVudC9kZXZpY2Uvb2JqZWN0IHdpbGwgc3Vydml2ZSB3aXRob3V0IGV4cGVyaWVuY2luZyBhbiBldmVudCBwYXN0IGEgZ2l2ZW4gYW1vdW50IG9mIHRpbWUuIFRoaXMgZnVuZGFtZW50YWwgZnVuY3Rpb24sIG9yIHJlbGF0aW9uc2hpcCwgaXMgcmVmZXJyZWQgdG8gYXMgdGhlICoqc3Vydml2YWwgZnVuY3Rpb24qKi4gV2hpbGUgdGhlcmUgYXJlIGEgbnVtYmVyIG9mIHN0YXRpc3RpY2FsIGFyZ3VtZW50cyBqdXN0aWZ5aW5nIHRoZSBmdW5kYW1lbnRhbCBleGlzdGVuY2Ugb2YgdGhlc2Ugc3Vydml2YWwgZnVuY3Rpb25zIChhbmQgdGhlaXIgYXBwcm9wcmlhdGVuZXNzIGluIGRlc2NyaWJpbmcgdGhlc2Uga2luZHMgb2YgcGhlbm9tZW5hKSwgSSB3aWxsIHJlZnJhaW4gZnJvbSBkZWx2aW5nIGludG8gdGhpcyB0b3BpYy4gVGhlcmUgYXJlIHNldmVyYWwgbWV0aG9kcy9tb2RlbHMgdGhhdCBhcmUgdXNlZCB0byBlc3RpbWF0ZSB0aGUgc3Vydml2YWwgZnVuY3Rpb24gb2YgdGltZS10by1ldmVudCBkYXRhOyBpbiB0aGlzIGRvY3VtZW50LCBJIHdpbGwgZm9jdXMgZXhjbHVzaXZlbHkgb24gb25lIG9mIHRoZSBtb3JlIGNvbW1vbiB0ZWNobmlxdWVzLCBhbmQgZXhwbGFpbiBpbiBkZXRhaWwgaG93IGl0IHdvcmtzLCB3aHkgaXQgaGFzIHN1Y2ggd2lkZXNwcmVhZCBhY2NsYWltLCBhbmQgc29tZSBvZiB0aGUgbGltaXRhdGlvbnMgdGhhdCBhcmUgaW5oZXJlbnQgaW4gaXRzIHVzZS4gDQoNCiMjIFRoZSBLYXBsYW4tTWVpZXIgRXN0aW1hdG9yDQoNClRoZSBLYXBsYW4tTWVpZXIgRXN0aW1hdG9yIGVtZXJnZWQgZnJvbSB0aGUgZ3JvdW5kYnJlYWtpbmcgcGFwZXIgb24gKk5vbnBhcmFtZXRyaWMgRXN0aW1hdGlvbiBGcm9tIEluY29tcGxldGUgT2JzZXJ2YXRpb25zKiBieSBFZHdhcmQgS2FwbGFuIGFuZCBQYXVsIE1laWVyIGluIDE5NTggKFtsaW5rXShodHRwczovL3dlYi5zdGFuZm9yZC5lZHUvfmx1dGlhbi9jb3Vyc2VwZGYvS01wYXBlci5wZGYpKS4gSW4gdGVybXMgb2YgaW1wYWN0LCB0aGlzIHBhcGVyIGlzIG9uZSBvZiB0aGUgbW9zdCBjaXRlZCBzY2llbnRpZmljIHBhcGVycyBvZiBhbGwgdGltZSwgYW5kIHdhcyByYW5rZWQgMTF0aCBpbiAyMDE0IHdpdGggYXBwcm94aW1hdGVseSAzOCw2MDAgY2l0YXRpb25zLCBhY2NvcmRpbmcgdG8gYW4gYXJ0aWNsZSBwdWJsaXNoZWQgaW4gdGhlIGpvdXJuYWwgKk5hdHVyZSogKFtsaW5rXShodHRwczovL3d3dy5uYXR1cmUuY29tL25ld3MvdGhlLXRvcC0xMDAtcGFwZXJzLTEuMTYyMjQpKS4gVGhlIGZvcm11bGEgdGhhdCB3YXMgcHJvcG9zZWQgaW4gdGhpcyBncm91bmRicmVha2luZyBwYXBlciAoYW5kIGxhdGVyIG5hbWVkIGFmdGVyIHRoZSB0d28gYXV0aG9ycykgc3VnZ2VzdGVkIHRoYXQgdGhlIFN1cnZpdmFsIGZ1bmN0aW9uICRTKHQpJCBjb3VsZCBiZSBub24tcGFyYW1ldHJpY2FsbHkgZXN0aW1hdGVkIGluIHRoZSBmb2xsb3dpbmcgd2F5Og0KDQokJA0KXGJlZ2lue2FycmF5fXtyY2x9DQogIFxoYXR7U30odCkgJj0mIFxkaXNwbGF5c3R5bGUgXHByb2Rfe2k6XCB0X2lcbGUgdH1cYmlnZygxLVxmcmFje2RfaX17bl9pfVxiaWdnKQ0KXGVuZHthcnJheX0NCiQkDQoNCldoZXJlICR0X2kkIGlzIGEgdGltZSBpbiB3aGljaCBhdCBsZWFzdCBvbmUgZXZlbnQgb2NjdXJyZWQsICRkX2kkIGlzIHRoZSBudW1iZXIgb2YgZXZlbnRzIHRoYXQgb2NjdXJyZWQgYXQgJHRfaSQsIGFuZCAkbl9pJCBpcyB0aGUgbnVtYmVyIG9mIG9iamVjdHMgb2YgaW50ZXJlc3QgdGhhdCBoYXZlIGJlZW4gKmtub3duKiB0byBoYXZlIG5vdCBoYWQgYW4gZXZlbnQgKGkuZS4gc3Vydml2ZWQpIHVwIHRvICR0X2kkLiBBcyBldmlkZW50IGZyb20gdGhlIGZvcm11bGEsIHRoaXMgaXMgYW4gZXhhbXBsZSBvZiBhIG5vbi1wYXJhbWV0cmljIHN0YXRpc3RpYy4gVG8gYmVzdCBnZXQgYSBmZWVsIGZvciBob3cgdGhpcyBmb3JtdWxhIHdvcmtzLCBpdCBpcyB1c2VmdWwgdG8gZXhhbWluZSB0aGlzIGZvcm11bGEgaW4gdGhlIGNvbnRleHQgb2YgYSBzaW1wbGUgZXhhbXBsZS4NCg0KDQpgYGB7cn0NCnRtcCA8LSBkYXRhLmZyYW1lKElEID0gc3ByaW50ZigiSUQlZCIsIDE6NSksIFRpbWUgPSAxOjUsIEV2ZW50ID0gMSkNCmtuaXRyOjprYWJsZSh0bXApDQpgYGANCg0KSW4gdGhpcyBzaW1wbGUgZXhhbXBsZSwgdGhlcmUgYXJlIGZpdmUgcGFydGljaXBhbnRzL29iamVjdHMgaW4gdGhlIHN0dWR5LiBUaGUgdGltZS10by1ldmVudCBkdXJhdGlvbiBvZiBJRDEgd2FzIDEgKHVuaXQgb2YgdGltZSkuIEZvciBJRDIsIGl0IHdhcyAyLCBhbmQgc28gb24uIEZyb20gdGhpcyB0aW1lLXRvLWV2ZW50IGRhdGEsIHdlIGNhbiBjYWxjdWxhdGUgJG5faSQgYW5kICRkX2kkIGlzIGEgdmVyeSBzaW1wbGUgZmFzaGlvbi4gRnJvbSB0aGVzZSBpbnB1dHMsIHRoZSBLYXBsYW4tTWVpZXIgZXN0aW1hdG9yIGlzIGRldGVybWluZWQgdG8gYmUgdGhlIGZvbGxvd2luZzoNCg0KDQpgYGB7cn0NCnRtcCA8LSBtdXRhdGUodG1wLCBuX2kgPSByZXYoY3Vtc3VtKHJlcCgxLCBuKCkpKSksIGRfaSA9IEV2ZW50KSAlPiUNCiAgbXV0YXRlKFNfdCA9IGN1bXByb2QoMSAtIGRfaS9uX2kpKQ0KdG1wIDwtIHJiaW5kLmZpbGwoZGF0YS5mcmFtZShUaW1lID0gMCwgU190ID0gMSwgbl9pID0gNSksIHRtcCkNCmcxIDwtIGdncGxvdChkYXRhID0gdG1wLCBhZXMoeCA9IFRpbWUsIHkgPSBTX3QpKSArIGdlb21fc3RlcCgpICsgbGFicyh5ID0gIlN1cnZpdmFsIEZ1bmN0aW9uIikgKyANCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxLCAwLjIpKSArIGZhY2V0X3dyYXAofiInVmFyaWFibGU6J35TKHQpIiwgbGFiZWxsZXIgPSBsYWJlbF9wYXJzZWQpDQpnMiA8LSBnZ3Bsb3QoZGF0YSA9IHJiaW5kLmZpbGwoZGF0YS5mcmFtZShUaW1lID0gNiwgbl9pID0gMCksIHRtcCksIGFlcyh4ID0gVGltZSAtIDEsIHkgPSBuX2kpKSArIGdlb21fc3RlcChjb2xvciA9ICJibHVlIikgKyANCiAgbGFicyh5ID0gIkNvdW50IE9mIFJlbWFpbmluZyIsIHggPSAiVGltZSIpICsgZmFjZXRfd3JhcCh+IidWYXJpYWJsZTonfm5baV0iLCBsYWJlbGxlciA9IGxhYmVsX3BhcnNlZCkgKyB4bGltKDAsIE5BKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNSwgMSksIGxhYmVscyA9IHNwcmludGYoIiUuMmYiLCBzZXEoMCwgNSwgMSkpKQ0KDQpnMyA8LSBnZ3Bsb3QoZGF0YSA9IG5hLm9taXQodG1wKSwgYWVzKHggPSBUaW1lLCB5ID0gZF9pKSkgKyBnZW9tX2JhcihmaWxsID0gInJlZCIsIHdpZHRoID0gMC4xNSwgc3RhdCA9ICJpZGVudGl0eSIpICsgDQogIGxhYnMoeSA9ICJDb3VudCBPZiBFdmVudHMiKSArIGZhY2V0X3dyYXAofiInVmFyaWFibGU6J35kW2ldIiwgbGFiZWxsZXIgPSBsYWJlbF9wYXJzZWQpICsgDQogIHhsaW0oMCwgTkEpICsgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwLjI1KSkpDQoNCmdyaWQuYXJyYW5nZShncm9icyA9IGxpc3QoZzEsIGcyLCBnMyksIGxheW91dF9tYXRyaXggPSBtYXRyaXgoYygxLDIsMSwzKSwgbnJvdyA9IDIsIGJ5cm93ID0gVFJVRSkpDQpgYGANCg0KTm90aWNlIHRoYXQgYXQgZWFjaCBzdGVwIGluIGFib3ZlIGdyYXBoaWMsIHRoZSBzdXJ2aXZhbCBmdW5jdGlvbiBkcm9wcGVkIGJ5IGFuIGFtb3VudCB0aGF0IHdhcyBlcXVhbCB0byB0aGUgY3VycmVudCBzdXJ2aXZhbCBmdW5jdGlvbiB2YWx1ZSBtdWx0aXBsaWVkIGJ5ICRkX2kvbl9pJC4gQXQgJHQ9MSQsICRuX2k9NSQsICRkX2k9MSQgYW5kICRcaGF0e1N9KHQpPTEkLCBhbmQgdGh1cyB0aGUgZnVuY3Rpb24gZHJvcHBlZCBieSAkMVx0aW1lcyAxLzUgPSAwLjIkLiBBdCAkdD0yJCwgJG5faT00JCwgJGRfaT0xJCBhbmQgJFxoYXR7U30odCk9MC44JCwgYW5kIHRodXMgdGhlIGZ1bmN0aW9uIGRyb3BwZWQgYnkgJDAuOFx0aW1lcyAxLzQgPSAwLjIkLiBBdCAkdD0zJCwgdGhlIGZ1bmN0aW9uIGRyb3BwZWQgYnkgJDAuNlx0aW1lcyAxLzMgPSAwLjIkLiBBbmQgc28gb24uIFRha2UgYSBtb21lbnQgdG8gZ28gYmFjayB0byB0aGUgZm9ybXVsYSBhbmQgdmVyaWZ5IHRoYXQgdGhpcyBiZWhhdmlvciBpcyBpbmRlZWQgcmVmbGVjdGVkIGJ5IHRoZSBwcm92aWRlZCBmb3JtdWxhdGlvbi4gDQoNClRoZSBpbnNpZ2h0IHRvIGJlIGdhaW5lZCBmcm9tIHRoaXMgaXMgdGhlIGZhY3QgdGhhdCB0aGUgc3Vydml2YWwgZnVuY3Rpb24gY291bnRzIGFsbCBwYXJ0aWNpcGFudHMgd2hvIGhhdmUgc3Vydml2ZWQgdXAgdW50aWwgYSBnaXZlbiB0aW1lL2R1cmF0aW9uICR0JCAoYXMgb3Bwb3NlZCB0byBvbmx5IHRob3NlIHBhcnRpY2lwYW50cyBhdCBvciBhcm91bmQgdGltZSAkdCQpLCBvbmx5IG5lZWRzIHRvIGJlIGNhbGN1bGF0ZWQgZm9yIHRoZSBwb2ludHMgaW4gd2hpY2ggdGhlcmUgd2FzIGFuIGV2ZW50IChiZWNhdXNlIHdoZW5ldmVyIHRoZXJlIGFyZSBubyBldmVudHMsIHRoZSBzdXJ2aXZhbCBmdW5jdGlvbiBkcm9wcyBieSAkXGhhdHtTfSh0KVx0aW1lcyAwL25faSA9IDAkIGFuZCB0aHVzIGNhbiBiZSBjb21wbGV0ZWx5IGlnbm9yZWQpLCBpdCBpcyBjdW11bGF0aXZlIChlbnN1cmluZyB0aGF0ICphbGwqIGRhdGEgcG9pbnRzIGNhbiBoYXZlIGFuIGVmZmVjdCBvbiB0aGUgZXN0aW1hdGVkIHJlc3VsdCwgc3VnZ2VzdGluZyB0aGF0IHRoZSBpbmZvcm1hdGlvbiB0aGF0IGlzIGF2YWlsYWJsZSBpbiB0aGUgZGF0YSBpcyB1c2VkIGVmZmVjdGl2ZWx5KSwgYW5kIGl0IGlzIHF1aXRlIGVhc3kgdG8gY2FsY3VsYXRlLiANCg0KV2h5IGRvZXMgdGhpcyBwcm9kdWN0IG9mIHJhdGlvcyBwcm92aWRlIGFjY3VyYXRlIGVzdGltYXRlcyBvZiB0aGUgc3Vydml2YWwgcHJvYmFiaWxpdHkgbGFyZ2VyIHRoYW4gc29tZSBnaXZlbiBkdXJhdGlvbiBvZiB0aW1lPyBUaGUgc2ltcGxlc3QgZXhwbGFuYXRpb24gb2YgdGhpcyBjYW4gYmUgZGVzY3JpYmVkIGZyb20gdGhlIHBlcnNwZWN0aXZlIG9mIGNvbmRpdGlvbmFsIHByb2JhYmlsaXR5LiBTdXBwb3NlIHRoYXQgeW91IGFyZSB0cnlpbmcgdG8gZmluZCAkXGhhdHtTfSgzKSA9IFxtYXRoc2Z7UH0oVCA+IDMpJCwgd2hlcmUgJFQkIGlzIHRoZSB0cnVlL3Vua25vd24gdGltZS10by1kZWF0aCBvZiB0aGUgb2JqZWN0IG9mIGludGVyZXN0LiBCeSB1c2luZyBjb25kaXRpb25hbCBwcm9iYWJpbGl0eSwgd2UgY2FuIGV4cGFuZCB0aGlzIG91dCBpbiB0aGUgZm9sbG93aW5nIHdheS4gIA0KJCQNClxiZWdpbnthcnJheX17cmNsbH0NCiAgXGhhdHtTfSgzKSAmPSYgXG1hdGhzZntQfShUID4gMykgDQogIFxcDQogICY9JiBcbWF0aHNme1B9KFQgPiAzXCBcY2FwIFwgVD4yKSAmIFx0ZXh0e1NpbmNlIH1cICBcbWF0aHNme1B9KFQgPiAzKSA9IFxtYXRoc2Z7UH0oVCA+IDMgXCBcY2FwIFwgVD4yKQ0KICBcXA0KICAmPSYgXG1hdGhzZntQfShUID4gM1wgfFwgVD4yKSBcdGltZXMgXG1hdGhzZntQfShUPjIpICYgXHRleHR7QmF5ZXMgVGhlb3JlbX0NCiAgXFwNCiAgJj0mIFxtYXRoc2Z7UH0oVCA+IDNcIHxcIFQ+MikgXHRpbWVzIFxtYXRoc2Z7UH0oVD4yXCB8XCBUPjEuNSkgXHRpbWVzIFxtYXRoc2Z7UH0oVD4xLjUpICYgLi4uDQpcZW5ke2FycmF5fQ0KJCQNCg0KVGhlIGZhY3QgdGhhdCB0aGUgc3Vydml2YWwgcHJvYmFiaWxpdHkgYXQgMyB5ZWFycyBvZiBhZ2UgY2FuIGJlIHdyaXR0ZW4gdG8gYmUgcHJvcG9ydGlvbmFsIHRvIHRoYXQgYXQgMiB5ZWFycyBvZiBhZ2UgY2FuIGJlIHVuZGVyc3Rvb2QgYXMgcmVmbGVjdGluZyB0aGUgZmFjdCB0aGF0IHRoZSBvYmplY3QgY2FuIG9ubHkgc3Vydml2ZSAzIHllYXJzIG9mIGFnZSBhZnRlciBmaXJzdCBzdXJ2aXZpbmcgMiB5ZWFycyBvZiBhZ2UuIE9uZSBjYW4gdGhlbiByZXBlYXQgdGhpcyBhcmd1bWVudCBhcyBtdWNoIGFzIG5lY2Vzc2FyeSB0byBvYnRhaW4gdGhlIGRlc2lyZWQgZXh0ZW5kZWQgcHJvZHVjdCBhcyB0aGUgcmVzdWx0LiBXaXRoIHRoaXMgaW4gbWluZCwgdGhlIG9yaWdpbmFsIGZvcm11bGEgc2hvdWxkIG1ha2UgYSBsb3QgbW9yZSBzZW5zZS4gDQoNCg0KV2l0aCB0aGlzIGludHJvZHVjdG9yeSBleGFtcGxlIG91dCBvZiB0aGUgd2F5LCB3ZSBjYW4gZGl2ZSBhIGxpdHRsZSBkZWVwZXIgaW50byB0aGUgbnVhbmNlcyBvZiB0aGlzIGZvcm11bGF0aW9uLCBhcyB3ZWxsIGFzIHRoZSByZWFzb25zIHdoeSBpdCBpcyBvbmUgb2YgdGhlIG1vc3QgcG9wdWxhciBhcHByb2FjaGVzIHRvIHN1cnZpdmFsIGFuYWx5c2lzLiBMZXQncyBzdGFydCB3aXRoIHRoZSBwcmltYXJ5IHByb2JsZW0gdGhhdCBLYXBsYW4gYW5kIE1laWVyIGJ1aWx0IHRoaXMgZXN0aW1hdG9yIHRvIGNvbWJhdDsgbmFtZWx5IG1pc3NpbmcgYW5kIGluY29tcGxldGUgdGltZS10by1ldmVudCBkYXRhLiANCg0KRm9yIGFueSBraW5kIG9mIHRpbWUtdG8tZXZlbnQgc2NlbmFyaW8sIHRoZXJlIGFyZSBhbHdheXMgYSBudW1iZXIgb2Ygb3B0aW9ucyB0aGF0IGEgZ2l2ZW4gcGF0aWVudC9vYmplY3Qtb2YtaW50ZXJlc3QgbWF5IGJlIGNoYXJhY3Rlcml6ZWQgYnkgYXQgYSBnaXZlbiBtb21lbnQgaW4gdGltZSAoYXMgcmVsZXZhbnQgdG8gdGhlIGFuYWx5c2lzKToNCg0KMS4gVGhlIGV2ZW50IGhhcyBoYXBwZW5lZCwgYW5kIHRoZSB0aW1lLXRvLWV2ZW50IGR1cmF0aW9uIGlzIGtub3duIChjb21wbGV0ZSBkYXRhKQ0KMi4gVGhlIGV2ZW50IGhhcyBub3QgaGFwcGVuZWQgKHlldCksIGFuZCB0aGUgZHVyYXRpb24gb2YgdGltZSB3aXRob3V0IGFuIGV2ZW50IGlzIGtub3duIChyaWdodC1jZW5zb3JlZCBkYXRhKQ0KMy4gVGhlIGV2ZW50IGhhcyBub3QgaGFwcGVuZWQgYW5kIG5ldmVyIHdpbGwgaGFwcGVuIGR1ZSB0byByZW1vdmFsIG9yIGxhY2sgb2YgY29tbXVuaWNhdGlvbi9rbm93bGVkZ2UsIGFuZCB0aGUga25vd24vY29uZmlybWVkIGR1cmF0aW9uIG9mIHRpbWUgd2l0aG91dCBhbiBldmVudCAoaS5lLiB0aW1lLXRvLWxhc3QgY29tbXVuaWNhdGlvbi9rbm93bGVkZ2UpIGlzIGtub3duIChyaWdodC1jZW5zb3JlZCBkYXRhKQ0KDQoNCioqTk9URSoqOiBPdGhlciBwb3NzaWJsZSBvcHRpb25zLCBzdWNoIGFzIGludGVydmFsIGNlbnNvcmluZywgYXJlIG5vdCBjb25zaWRlcmVkIGhlcmUuDQoNCg0KVGhlIHBvd2VyIGJlaGluZCB0aGUgS2FwbGFuLU1laWVyIEVzdGltYXRvciBpcyB0aGF0IHVubGlrZSBvdGhlciBtb3JlIG5haXZlIHN1cnZpdmFsIGZ1bmN0aW9uIGVzdGltYXRpb24gYXBwcm9hY2hlcywgd2hpY2ggbWF5IG9ubHkgYmUgYWJsZSB0byByZWxpYWJsZSBleHRyYWN0IGluZm9ybWF0aW9uIGZyb20gZGF0YSBzb3VyY2VzL3JlY29yZHMgdGhhdCBhcmUgJ2NvbXBsZXRlJywgdGhlIEthcGxhbiBNZWllciBlc3RpbWF0b3IgY2FuIGJlIHByb3ZlbiB0byBiZSBhYmxlIHRvIGVmZmVjdGl2ZWx5IG1ha2UgdXNlIG9mIGJvdGggY29tcGxldGUgYW5kIHJpZ2h0LWNlbnNvcmVkIGRhdGEgdG8gY3JhZnQgdGhlIGVzdGltYXRlZCBzdXJ2aXZhbCBmdW5jdGlvbi4gU3BlY2lmaWNhbGx5LCB0aGlzIGVuc3VyZXMgdGhhdCBub25lIG9mIHRoZSBkYXRhIGlzIHRocm93biBvdXQgZHVlIHRvIHRoZSBpbmNvbXBsZXRlbmVzcyBvZiB0aGUgZGF0YSBvYnNlcnZhdGlvbnMuIFRoaXMsIGluIGNvbWJpbmF0aW9uIHdpdGggaXRzIHN0YXR1cyBhcyBhIG5vbi1wYXJhbWV0cmljIGVzdGltYXRvciwgaXMgYXJndWFibHkgdGhlIHJlYXNvbiBiZWhpbmQgaXRzJyBwcm9mb3VuZCBwb3B1bGFyaXR5IGluIHByYWN0aWNhbCBhcHBsaWNhdGlvbnMgKHBhcnRpY3VsYXJseSBtZWRpY2luZSByZXNlYXJjaCksIGFzIG1vcmUgbGlrZWx5IHRoYW4gbm90IHlvdSB3aWxsICoqbmV2ZXIqKiBoYXZlIHRpbWUtdG8tZXZlbnQgZGF0YXNldHMgdGhhdCBhcmUgY29tcGxldGUgKGluIHRoZSBzZW5zZSB0aGF0IGFsbCByZWNvcmRzIGFyZSBjb21wbGV0ZSkuIEFzIGEgc2ltcGxlLCBidXQgcHJvZm91bmQsIGV4YW1wbGUsIHN1cHBvc2UgeW91IHdhbnQgdG8gYmV0dGVyIHVuZGVyc3RhbmQgaHVtYW4gbGlmZXRpbWVzIChpLmUuIHRpbWUtdG8tZGVhdGgpLiBJZiB5b3UgZG9uJ3QgdGhyb3cgb3V0IGFueSBwb3RlbnRpYWwgZGF0YSwgeW91IHdpbGwgbmV2ZXIgaGF2ZSBhIGNvbXBsZXRlIGRhdGFzZXQgb2YgdGltZS10by1kZWF0aCBkYXRhLCBzaW1wbHkgYmVjYXVzZSB5b3UgeW91cnNlbGYgYXJlIHN0aWxsIGFsaXZlIChhbmQgdGh1cyB5b3VyIHRpbWUtdG8tZGVhdGggZHVyYXRpb24gaXMgbm90IGtub3duKS4gV2FpdGluZyB1bnRpbCBzdWNoIGEgdGltZSB0aGF0IG9uZSBoYXMgY29tcGxldGUgZGF0YSBpbiB0aGlzIGNhc2UgKGFuZCBpbiBtYW55IG90aGVycykgaXMgdGh1cyBjb21wbGV0ZWx5IHJpZGljdWxvdXMuIFJhdGhlciwgaWYgdGhlIGFwcHJvYWNoIGJlaW5nIHVzZWQgdHJ1bHkgZG9lcyByZXF1aXJlIG5vdGhpbmcgYnV0IGNvbXBsZXRlIGRhdGEsIHRoZW4gYWxsIHRoZSBkYXRhIHJlY29yZHMgd2l0aCBpbmNvbXBsZXRlIGluZm9ybWF0aW9uIHdvdWxkIG5lZWQgdG8gYmUgcmVtb3ZlZCBmcm9tIGNvbnNpZGVyYXRpb24sIHJlZHVjaW5nIHRoZSBzaXplIG9mIHRoZSBkYXRhIHNhbXBsZSBhbmQsIGFzIGEgY29uc2VxdWVuY2UsIHRoZSBhY2N1cmFjeSBvZiB0aGUgZmluYWwgcmVzdWx0LiBIb3dldmVyLCB3aXRoIHRoZSBLYXBsYW4tTWVpZXIgRXN0aW1hdG9yLCB0aGlzIGlzIG5vdCBhbiBpc3N1ZSwgYXMgaXQgd2FzIHNwZWNpZmljYWxseSBmb3JtdWxhdGVkIGluIHN1Y2ggYSAgd2F5IHRoYXQgZXZlbiBpbmNvbXBsZXRlIGRhdGEgcmVjb3JkcyBjYW4gYmUgZWZmZWN0aXZlbHkgbWFkZSB1c2Ugb2YuIA0KDQpJbiBmYWN0LCB3aXRoIHJlc3BlY3QgdG8gdGhlIGVzdGltYXRlZCBzdXJ2aXZhbCBmdW5jdGlvbiB1c2luZyB0aGUgS2FwbGFuLU1laWVyIEVzdGltYXRvciwgbm9uZSBvZiB0aGVzZSBjZW5zb3JlZCBkYXRhIHJlY29yZHMgYWN0dWFsbHkgY2F1c2UgdGhlIHN1cnZpdmFsIGN1cnZlIHRvIGRyb3AsIGFzIHdlIGhhdmUgcHJldmlvdXNseSBkZW1vbnN0cmF0ZWQgdGhhdCB0aGUgb25seSAnZHJvcHMnIGluIHRoZSBzdXJ2aXZhbCBjdXJ2ZSBvY2N1ciB3aGVuIHRoZXJlIGFyZSBhIG5vbi16ZXJvIG51bWJlciBvZiAnZXZlbnRzJyBhdCBzb21lIHRpbWUvZHVyYXRpb24gJHRfaSQuIEhvd2V2ZXIsIHRoZXkgZG8gc3RpbGwgcGxheSBhIHJvbGUgaW4gdGhlIG92ZXJhbGwgY2FsY3VsYXRpb24gYnkgYWZmZWN0aW5nIHRoZSB2YWx1ZSBvZiAkbl9pJCwgb3IgdGhlIG51bWJlciBvZiBvYmplY3RzIG9mIGludGVyZXN0IHRoYXQgaGF2ZSBiZWVuIG9ic2VydmVkIHRvIGhhdmUgc3Vydml2ZWQgd2l0aG91dCBhbiBldmVudCBmb3IgYSBkdXJhdGlvbiBsb25nZXIgdGhhbiAkdF9pJC4gVGhpcyBpcyBiZWNhdXNlLCB3aGlsZSB0aGUgdHJ1ZSB0aW1lLXRvLWV2ZW50IGR1cmF0aW9uIG9mIHRoZXNlIGNlbnNvcmVkIG9iamVjdHMgbWF5IG5vdCBiZSBrbm93biwgaXQgaXMga25vd24gdGhhdCB0aGV5IG11c3QgYmUgbGFyZ2VyIHRoYW4gdGhlIGN1cnJlbnQgYWdlIG9mIHRoZSBvYmplY3RzLiBBcyBhIGRlbW9uc3RyYXRpb24gb2YgdGhlIGVmZmVjdCBvZiB0aGVzZSBjZW5zb3JlZCBkYXRhIHJlY29yZHMsIGlmIHdlIG1vZGlmeSBvdXIgb3JpZ2luYWwgc2ltcGxlIGV4YW1wbGUgc3VjaCB0aGF0IHRoZSBJRDMgaXMgbm8gbG9uZ2VyIGFuICdldmVudCcsIGJ1dCByYXRoZXIgYSByaWdodC1jZW5zb3JlZCBkYXRhIHBvaW50LCB0aGVuIHRoZSByZXN1bHQgaXMgYXMgZm9sbG93czoNCg0KDQpgYGB7cn0NCnRtcCA8LSBkYXRhLmZyYW1lKElEID0gc3ByaW50ZigiSUQlZCIsIDE6NSksIFRpbWUgPSAxOjUsIEV2ZW50ID0gYygxLDEsMCwxLDEpKQ0Ka25pdHI6OmthYmxlKHRtcCkNCmBgYA0KDQpIZXJlLCB0aGUgcmlnaHQtY2Vuc29yZWQgZGF0YSByZWNvcmQgaXMgc3BlY2lmaWVkIGJ5IGVuc3VyaW5nIHRoZSB2YWx1ZSBpbiB0aGUgKkV2ZW50KiBjb2x1bW4gYXNzb2NpYXRlZCB3aXRoIHRoaXMgcmVjb3JkIChuYW1lbHkgSUQzKSBpcyB6ZXJvLiANCg0KYGBge3J9DQp0bXAgPC0gbXV0YXRlKHRtcCwgbl9pID0gcmV2KGN1bXN1bShyZXAoMSwgbigpKSkpLCBkX2kgPSBFdmVudCkgJT4lDQogIG11dGF0ZShTX3QgPSBjdW1wcm9kKDEgLSBkX2kvbl9pKSkNCnRtcCA8LSByYmluZC5maWxsKGRhdGEuZnJhbWUoVGltZSA9IDAsIFNfdCA9IDEsIG5faSA9IDUpLCB0bXApDQpnMSA8LSBnZ3Bsb3QoZGF0YSA9IHRtcCwgYWVzKHggPSBUaW1lLCB5ID0gU190KSkgKyBnZW9tX3N0ZXAoKSArIGxhYnMoeSA9ICJTdXJ2aXZhbCBGdW5jdGlvbiIpICsgDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgMC4yKSkgKyBmYWNldF93cmFwKH4iJ1ZhcmlhYmxlOid+Uyh0KSIsIGxhYmVsbGVyID0gbGFiZWxfcGFyc2VkKSArIA0KICBnZW9tX3BvaW50KGRhdGEgPSBzdWJzZXQodG1wLCBFdmVudCA9PSAwKSwgc2hhcGUgPSAzLCBzaXplID0gMi41KSArDQogIGdlb21fc2VnbWVudChkYXRhID0gZGF0YS5mcmFtZSh4ID0gMS41LCB4ZW5kID0gMi45LCB5ID0gMC4zLCB5ZW5kID0gMC41NzUpLCBhZXMoeCA9IHgsIHkgPSB5LCB4ZW5kID0geGVuZCwgeWVuZCA9IHllbmQpLA0KICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImxpbmVzIikpLCBzaXplID0gMSkgKw0KICBhbm5vdGF0ZSgibGFiZWwiLCB4ID0gMS41LCB5ID0gMC4zLCBsYWJlbCA9ICJDZW5zb3JlZFxuRGF0YSBQb2ludCIsIHNpemUgPSA1KQ0KZzIgPC0gZ2dwbG90KGRhdGEgPSByYmluZC5maWxsKGRhdGEuZnJhbWUoVGltZSA9IDYsIG5faSA9IDApLCB0bXApLCBhZXMoeCA9IFRpbWUgLSAxLCB5ID0gbl9pKSkgKyBnZW9tX3N0ZXAoY29sb3IgPSAiYmx1ZSIpICsgDQogIGxhYnMoeSA9ICJDb3VudCBPZiBSZW1haW5pbmciLCB4ID0gIlRpbWUiKSArIGZhY2V0X3dyYXAofiInVmFyaWFibGU6J35uW2ldIiwgbGFiZWxsZXIgPSBsYWJlbF9wYXJzZWQpICsgeGxpbSgwLCBOQSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDUsIDEpLCBsYWJlbHMgPSBzcHJpbnRmKCIlLjJmIiwgc2VxKDAsIDUsIDEpKSkNCg0KZzMgPC0gZ2dwbG90KGRhdGEgPSBuYS5vbWl0KHRtcCksIGFlcyh4ID0gVGltZSwgeSA9IGRfaSkpICsgZ2VvbV9iYXIoZmlsbCA9ICJyZWQiLCB3aWR0aCA9IDAuMTUsIHN0YXQgPSAiaWRlbnRpdHkiKSArIA0KICBsYWJzKHkgPSAiQ291bnQgT2YgRXZlbnRzIikgKyBmYWNldF93cmFwKH4iJ1ZhcmlhYmxlOid+ZFtpXSIsIGxhYmVsbGVyID0gbGFiZWxfcGFyc2VkKSArIA0KICB4bGltKDAsIE5BKSArIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4yNSkpKQ0KDQpncmlkLmFycmFuZ2UoZ3JvYnMgPSBsaXN0KGcxLCBnMiwgZzMpLCBsYXlvdXRfbWF0cml4ID0gbWF0cml4KGMoMSwyLDEsMyksIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpKQ0KYGBgDQoNClRoZXJlIGFyZSBhIGZldyB0aGluZ3MgdG8gbm90ZSBoZXJlLiBGaXJzdCwgYXQgJHQ9MyQsIHRoZXJlIHdhcyBubyBkcm9wIGluIHRoZSBLYXBsYW4tTWVpZXIgc3Vydml2YWwgZnVuY3Rpb24gZXN0aW1hdGUuIFRoaXMgaXMgYmVjYXVzZSB0aGVyZSB3ZXJlIG5vIGV2ZW50cyBhdCAkdD0zJCAoaS5lLiB3aGVuICR0X2k9MyQsICRkX2k9MCQsIGFzIGNhbiBiZSBzZWVuIGluIHRoZSBzdWItZ3JhcGggZm9yICRkX2kkKS4gU2Vjb25kLCB0aGVyZSBpcyBubyBjaGFuZ2UgaW4gdGhlIGdyYXBoIG9mICRuX2kkIGZvciB0aGlzIHNsaWdodGx5IG1vZGlmaWVkIHNhbXBsZSBkYXRhc2V0LiBUaGlyZCwgdGhlIHJlZHVjdGlvbiBpbiB0aGUgc3Vydml2YWwgZnVuY3Rpb24gd2FzIGxhcmdlciBhdCAkdD00JCB0aGFuIGl0IHdhcyBhdCAkdD0yJC4gU3BlY2lmaWNhbGx5LCB3aGVuICR0X2k9NCQsIHRoZSBzdXJ2aXZhbCBmdW5jdGlvbiBhdCB0aGlzIHRpbWUgd2FzICRcaGF0e1N9KHQpPTAuNiQsIHdpdGggJGRfaT0xJCBhbmQgJG5faT0yJC4gUGx1Z2dpbmcgaW4sIHdlIGZpbmQgdGhhdCB0aGUgb3ZlcmFsbCBzaXplIG9mIHRoZSBkcm9wIHNob3VsZCBiZSBlcXVhbCB0byAkMC42XHRpbWVzMS8yPTAuMyQuIEl0J3MgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCB0aGUgaW5mb3JtYXRpb24gcHJvdmlkZWQgYnkgdGhlIGNlbnNvcmVkIGRhdGEgcmVjb3JkIGJlaGF2ZWQgZXhhY3RseSBsaWtlIHRoZSBwcmV2aW91cyB2ZXJzaW9uIChpbiB3aGljaCBhbGwgdGltZS10by1ldmVudCBtZWFzdXJlbWVudHMgd2VyZSBrbm93bikgdXAgdG8gdGhlIHBvaW50IHdoZXJlIG5vIGZ1cnRoZXIgaW5mb3JtYXRpb24gd2FzIGtub3duIHJlZ2FyZGluZyB0aGUgdGltZS10by1ldmVudCBvZiB0aGUgZ2l2ZW4gcmVjb3JkIChpLmUuIGl0IGlzIGtub3cgdG8gYmUgbGFyZ2VyIHRoYW4gMywgYnV0IG5vdGhpbmcgbW9yZSB0aGFuIHRoYXQpLiBBdCB0aGUgc2FtZSB0aW1lLCBubyBhc3N1bXB0aW9ucyByZWdhcmRpbmcgdGhlIHRydWUgdGltZS10by1ldmVudCBkdXJhdGlvbiBhcmUgbWFkZSwgd2hpY2ggaXMgd2h5IHRoZSBjdXJ2ZSBkaWZmZXJlZCBzbGlnaHRseSBhZnRlciAkdD0zJCBjb21wYXJlZCB0byB0aGUgb3JpZ2luYWwgdmVyc2lvbiAoYmVjYXVzZSBvZiB0aGlzIGluY29tcGxldGUvdW5rbm93biBpbmZvcm1hdGlvbikuIFRoaXMgZGVtb25zdHJhdGVzIGhvdyB1c2VmdWwgaW5mb3JtYXRpb24gY2FuIGJlIGV4dHJhY3RlZCBldmVuIGZyb20gaW5jb21wbGV0ZSBkYXRhIHJlY29yZHMgdXNpbmcgdGhlIEthcGxhbi1NZWllciBFc3RpbWF0b3IgaW4gc3VjaCBhIHdheSB0aGF0IG5vIGltcGxpY2l0IGFzc3VtcHRpb25zIHJlZ2FyZGluZyB1bmtub3duIGluZm9ybWF0aW9uIGFyZSBtYWRlLg0KDQoNCg0KIyMjIFByYWN0aWNhbCBDb25zaWRlcmF0aW9ucw0KDQpJbiBhZGRpdGlvbiB0byBhbGwgdGhhdCB3ZSBoYXZlIGRpc2N1c3NlZCB1cCB0byB0aGlzIHBvaW50LCB0aGVyZSBhcmUgYWxzbyBhIG51bWJlciBvZiBwcmFjdGljYWwgY29uc2lkZXJhdGlvbnMgdGhhdCBvbmUgc2hvdWxkIGJlIGF3YXJlIG9mIHdoZW4gdXNpbmcgYW5kIGFwcGx5aW5nIHRoZSBLYXBsYW4tTWVpZXIgRXN0aW1hdG9yIHRvIHRpbWUtdG8tZXZlbnQgZGF0YS4gVGhlIGZpcnN0IHRoYXQsIGxpa2UgYWxsIG1hdGhlbWF0aWNhbCBtb2RlbHMsIHRoZSBzYW1wbGUgc2l6ZSBhbmQgcXVhbGl0eSBvZiB0aGUgZGF0YSBtYXR0ZXIuIFRvIGJlIG1vcmUgbWF0aGVtYXRpY2FsbHkgcHJlY2lzZSwgdGhlIGNvbmZpZGVuY2Ugb2YgdGhlIHJlc3VsdGluZyBjdXJ2ZSBmaXQgd2lsbCBkZXBlbmQgb24gdGhlIGRhdGEgdGhhdCBpcyB1c2VkLiBJdCBpcyBzdGFuZGFyZCBwcmFjdGljZSB0byB1c2UgYSA5NSUgY29uZmlkZW5jZSBsZXZlbCB3aGVuIGNvbnN0cnVjdGluZyBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIGVzdGltYXRlZCBmaXQuIFRoZSBleGFjdCBkZXRhaWxzIHJlZ2FyZGluZyBob3cgdGhlc2UgY29uZmlkZW5jZSBpbnRlcnZhbHMgYXJlIGNvbnN0cnVjdGVkIGxpZSBvdXRzaWRlIHRoZSBzY29wZSBvZiB0aGlzIGRvY3VtZW50OyBob3dldmVyLCBhdCBhIGhpZ2gtbGV2ZWwsIGxhcmdlciBkYXRhc2V0cyB3aXRoIGZldyBjZW5zb3JlZCBkYXRhIHJlY29yZHMgaGF2ZSB0aGUgdGlnaHRlc3QgY29uZmlkZW5jZSBpbnRlcnZhbHMgKGkuZS4gbG93IHVuY2VydGFpbnR5KSwgd2hpbGUgc21hbGwgZGF0YXNldHMgd2l0aCBtYW55IGNlbnNvcmVkIGRhdGEgcmVjb3JkcyBoYXZlIHRoZSBsYXJnZXN0IGNvbmZpZGVuY2UgaW50ZXJ2YWxzIChpLmUuIGhpZ2ggdW5jZXJ0YWludHkpLiBUaGlzIGlzIGRlbW9uc3RyYXRlZCBpbiB0aGUgZXhhbXBsZSBiZWxvdywgdXNpbmcgdGltZS10by1ldmVudCBzdXJ2aXZhbCBkYXRhIGRyYXduIGZyb20gYSBHZW9tZXRyaWMgZGlzdHJpYnV0aW9uIGFuZCBjZW5zb3JpbmcgZGV0ZXJtaW5lZCBieSBhIEJpbm9taWFsIGRpc3RyaWJ1dGlvbiB3aXRoIHByb2JhYmlsaXR5ICRwJC4NCg0KJCQNClxiZWdpbnthcnJheX17cmNsfQ0KICBUXHNpbSBcdGV4dHtHZW9tfSgwLjA1KSAmJiBFX3t2ZW50fSBcc2ltIEIoMSwgcCkNClxlbmR7YXJyYXl9DQokJA0KDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShzdXJ2aXZhbCkNCmxpYnJhcnkoc3Vydm1pbmVyKQ0KZ2VuU3VydkdyYXBoaWMgPC0gZnVuY3Rpb24oc3Bsb3QpIHsNCiAgc3RpdCA8LSAiS2FwbGFuLU1laWVyIEVzdGltYXRvciINCiAgeWxhYiA8LSAiU3Vydml2YWwgRnVuY3Rpb24iDQogIHAxIDwtIHNwbG90JHBsb3QgKyBmYWNldF93cmFwKH5nc3ViKCJ2ZXI9IiwgIiIsIHN0cmF0YSkpICsgDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCiAgaWYgKCFpcy5udWxsKHNwbG90JHBsb3QkbGFiZWxzJHRpdGxlKSkgew0KICAgIHAxIDwtIHAxICsgbGFicyhzdWJ0aXRsZSA9IGdzdWIoIjo6LioiLCAiIiwgc3Bsb3QkcGxvdCRsYWJlbHMkdGl0bGUpLCB0aXRsZSA9IHN0aXQsIHkgPSB5bGFiKSArIA0KICAgICAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgaGp1c3QgPSAwLjUpKQ0KICB9IGVsc2Ugew0KICAgIHAxIDwtIHAxICsgbGFicyh0aXRsZSA9IHN0aXQsIHkgPSB5bGFiKQ0KICB9DQogIHJldHVybihwMSkNCn0NCmBgYA0KDQoNCg0KYGBge3J9DQpzZXQuc2VlZCgxMDAwMCkNCmRhdGEgPC0gcmJpbmQuZmlsbChsaXN0KA0KICBkYXRhLmZyYW1lKFRpbWUgPSByZ2VvbSgxMDAsIDAuMDUpLCBjZW5zID0gcmJpbm9tKDEwMCwgMSwgMC44MCksIHZlciA9ICJEYXRhIFN1cHBsaWVkOiBMYXJnZSBTYW1wbGUgKE4gPSAxMDApLCBGZXcgQ2Vuc29yZWQgKHAgPSAwLjIpIiksDQogIGRhdGEuZnJhbWUoVGltZSA9IHJnZW9tKDEwMCwgMC4wNSksIGNlbnMgPSByYmlub20oMTAwLCAxLCAwLjIwKSwgdmVyID0gIkRhdGEgU3VwcGxpZWQ6IExhcmdlIFNhbXBsZSAoTiA9IDEwMCksIE1hbnkgQ2Vuc29yZWQgKHAgPSAwLjgpIiksDQogIGRhdGEuZnJhbWUoVGltZSA9IHJnZW9tKDEwLCAwLjA1KSwgY2VucyA9IHJiaW5vbSgxMCwgMSwgMC44MCksIHZlciA9ICJEYXRhIFN1cHBsaWVkOiBTbWFsbCBTYW1wbGUgKE4gPSAxMCksIEZldyBDZW5zb3JlZCAocCA9IDAuMikiKSwNCiAgZGF0YS5mcmFtZShUaW1lID0gcmdlb20oMTAsIDAuMDUpLCBjZW5zID0gcmJpbm9tKDEwLCAxLCAwLjIwKSwgdmVyID0gIkRhdGEgU3VwcGxpZWQ6IFNtYWxsIFNhbXBsZSAoTiA9IDEwKSwgTWFueSBDZW5zb3JlZCAocCA9IDAuOCkiKQ0KKSkgDQpmaXQgPC0gc3VydmZpdChTdXJ2KFRpbWUsIGNlbnMpIH4gdmVyLCBkYXRhID0gZGF0YSkNCmdlblN1cnZHcmFwaGljKGdnc3VydnBsb3QoZml0ID0gZml0LCBkYXRhID0gZGF0YSwgZ2d0aGVtZSA9IHRoZW1lKCksIGNvbmYuaW50ID0gVFJVRSkpDQpgYGANCg0KDQoNCiMjIENvbmNsdXNpb24NCg0KSnVzdCBhcyBhbnkgb3RoZXIgbWF0aGVtYXRpY2FsIG1vZGVsLCB0aGVyZSBhcmUgcHJvcyBhbmQgY29ucyBhc3NvY2lhdGVkIHdpdGggdXNpbmcgdGhlIEthcGxhbi1NZWllciBFc3RpbWF0b3IgdG8gZXN0aW1hdGUgdGhlIHN1cnZpdmFsIGZ1bmN0aW9uIG9mIHNvbWUgcGhlbm9tZW5vbiBvZiBpbnRlcmVzdC4gVGhlIGZhY3QgdGhhdCBpdCBpcyBhIG5vbi1wYXJhbWV0cmljIGFwcHJvYWNoIHRvIGVzdGltYXRpbmcgdGhlIHN1cnZpdmFsIGZ1bmN0aW9uIGlzIHNvbWV0aGluZyB0aGF0IG1ha2VzIGl0IHBhcnRpY3VsYXJseSBkZXNpcmFibGUgaW4gbWFueSBjYXNlcyBmb3IgYSBudW1iZXIgb2YgcmVhc29ucy4gQXMgYSBub24tcGFyYW1ldHJpYyBlc3RpbWF0b3IsIGl0IG1ha2VzIHZlcnkgZmV3IGltcGxpY2l0IGFzc3VtcHRpb25zIHJlZ2FyZGluZyB0aGUgcGhlbm9tZW5vbiBvZiBpbnRlcmVzdCwgYW5kIHRodXMgbWF5IGJlIHVzZWQgZm9yIGEgd2lkZSByYW5nZSBvZiB0aW1lLXRvLWV2ZW50IGFwcGxpY2F0aW9ucy4gUGVyZm9ybWFuY2Utd2lzZSwgaXQgaXMgYWxzbyBxdWl0ZSByb2J1c3QgYW5kIGlzIHVuYmlhc2VkLCBhdCBsZWFzdCB1cCB0byB0aGUgbGFzdCBvYnNlcnZlZCBldmVudCBpbiB0aGUgcHJvdmlkZWQgZGF0YSAobm90ZSB0aGF0IHRoaXMgbWF5IG5vdCBiZSB0aGUgbWF4aW11bSBvYnNlcnZlZCBkdXJhdGlvbiBpbiB0aGUgZGF0YSBpZiB0aGUgcmVjb3JkcyB3aXRoIHRoZSBsYXJnZXN0IGR1cmF0aW9uIGFyZSBjZW5zb3JlZCkuIEFzIGFuIGFkZGl0aW9uYWwgcGVyaywgdGhlIEthcGxhbi1NZWllciBFc3RpbWF0b3IgY2FuIGJlIGRlbW9uc3RyYXRlZCB0byBiZSB0aGUgTWF4aW11bS1MaWtlbGlob29kIEVzdGltYXRvciBmb3IgdGhlc2Uga2luZHMgb2YgdGltZS10by1ldmVudCBhbmFseXNlcyAoc3BlY2lmaWNhbGx5LCBpdCBpcyB0aGUgTUxFIG9mIHRoZSBIYXphcmQgRnVuY3Rpb24pLiANCg0KRGVzcGl0ZSBhbGwgdGhpcywgdGhlIEthcGxhbi1NZWllciBFc3RpbWF0b3IgbWF5IG5vdCBhbHdheXMgYmUgdGhlIG9wdGltYWwgY2hvaWNlIGZvciBhIGdpdmVuIHRpbWUtdG8tZXZlbnQgYXBwbGljYXRpb24uIEZvciBleGFtcGxlLCB0aGVyZSBhcmUgbWFueSBhcHBsaWNhdGlvbnMgaW4gdGhlIHdvcmxkIG9mIGVuZ2luZWVyaW5nIGluIHdoaWNoIGVub3VnaCBpcyBrbm93biBhYm91dCB0aGUgcHJvYmxlbSBhdCBoYW5kIHN1Y2ggdGhhdCBwYXJhbWV0cmljIGFwcHJvYWNoZXMgdG8gdGhpcyBraW5kIG9mIHN1cnZpdmFsIGFuYWx5c2lzIGFyZSBub3Qgb25seSBwb3NzaWJsZSwgYnV0IGFsc28gaGF2ZSBiZXR0ZXIgcGVyZm9ybWFuY2UgY29tcGFyZWQgdG8gdGhlaXIgbm9uLXBhcmFtZXRyaWMgY291bnRlcnBhcnRzLiBPZiBwYXJ0aWN1bGFybHkgbm90ZSBpbiB0aGlzIHJlc3BlY3QgaXMgdGhlIGltcHJvdmVtZW50IGluIHN0YXRpc3RpY2FsICdQb3dlcicgdGhhdCBtYW55IHBhcmFtZXRyaWMgYXBwcm9hY2hlcyBwcm92aWRlIGV2ZW4gd2l0aCB0aGUgc2FtZSBpbnB1dCBkYXRhLiBXaGF0J3MgbW9yZSwgdGhlIEthcGxhbi1NZWllciBFc3RpbWF0b3IgaXMgbm90IHBhcnRpY3VsYXIgZmxleGlibGUgd2l0aCByZXNwZWN0IHRvIGFkanVzdGluZyBmb3IgY292YXJpYXRlcyB0aGF0IG1heSBhZmZlY3QgdGhlIHVuZGVybHlpbmcgc3Vydml2YWwgZnVuY3Rpb24gb2YgaW50ZXJlc3QuIEFuZCBsYXN0bHksIHRoZSBLYXBsYW4tTWVpZXIgRXN0aW1hdG9yIGlzIG5vdCBhYmxlIHRvIGFjY291bnQgZm9yIGNlbnNvcmVkIGRhdGEgcmVjb3JkcyB0aGF0IGFyZSBub3QgcmlnaHQtY2Vuc29yZWQgKGUuZy4gbGVmdCBvciBpbnRlcnZhbC1jZW5zb3JlZCBkYXRhKS4gDQoNCg0KSW4gY29uY2x1c2lvbiwgdGhlIEthcGxhbi1NZWllciBlc3RpbWF0ZSBpcyBhIHBvd2VyZnVsIHRvb2wgdGhhdCBjYW4gYmUgdXNlZCB0byBkZXZlbG9wIGFuIGVzdGltYXRlIG9mIHRoZSBzdXJ2aXZhbCBmdW5jdGlvbiBkZWZpbmluZyBhIHNwZWNpZmljIHByb2Nlc3Mgb3IgcGhlbm9tZW5vbiB3aGVuIGRlYWxpbmcgd2l0aCB0aW1lLXRvLWV2ZW50IGRhdGEuIEJlaW5nIGFibGUgdG8gZXN0aW1hdGUgdGhlIHN1cnZpdmFsIGZ1bmN0aW9uIGlzIHZlcnkgdXNlZnVsIGFuZCBwb3dlcmZ1bCwgYXMgaXQgY2FuIGJlIHVzZWQgZm9yIGEgd2lkZSByYW5nZSBvZiBhcHBsaWNhdGlvbnMsIGluY2x1ZGluZyBwcmVkaWN0aW5nIGZ1dHVyZSBwZXJmb3JtYW5jZSAoc3VjaCBhcyB0aGUgbWVjaGFuaWNhbCBmYWlsdXJlIHJhdGUgb2Ygc2VydmVycyBpbiBhIGRhdGFjZW50ZXIsIG9yIHRoZSBtYWludGVuYW5jZSBuZWVkcyBvZiBhIG51bWJlciBvZiBhc3NldHMgaW4gdGhlIG5leHQgdHdvIHllYXJzKSwgb3IgY29tcGFyaW5nIHRoZSBzdXJ2aXZhbCByYXRlcyBiZXR3ZWVuIGRpZmZlcmVudCBkYXRhIHN1Yi1wb3B1bGF0aW9ucyAoc3VjaCBhcyB0aGUgbG9uZy10ZXJtIHBlcmZvcm1hbmNlIG9mIHR3byBkaWZmZXJlbnQgdmFjY2luZXMgd2l0aCByZXNwZWN0IHRvIGNvbmZlcnJpbmcgaW1tdW5pdHkgb3IgcmVzaXN0YW5jZSB0byBhIHBhdGhvZ2VuKS4NCg0KDQoNCmBgYHtyLGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgcmVzdWx0cz0naG9sZCd9DQpvcHRpb25zKHdpZHRoID0gMTAwKQ0KY2F0KCJSIFNlc3Npb24gSW5mb3JtYXRpb246XG4iKQ0Kc2Vzc2lvbkluZm8oKQ0KYGBgDQoNCg0KDQoNCg==