Note: Some of the code
has been omitted to enhance readability.
The following terms
might be used interchangeably with each other:
Rows = Observations =
Records
Columns = Variables =
Features
Purpose and
Objectives:
The purpose of this project is to showcase my knowledge in Data
Analytics, focusing on the application of machine learning
techniques for text classification. My objective is to
attempt predicting the sentiment —positive, neutral, or
negative— of individuals based on their Twitter messages in regards to
COVID-19, using those words that get repeated 100 times or
more. The model that will be used here is the
Multinomial Naive Bayes.
Data
Collection
Loading the
data:
training <- read.csv(file = "Corona_NLP_train.csv", header = TRUE, sep = ",", stringsAsFactors = FALSE, strip.white = TRUE, encoding = "latin1")
#encoding = "UTF-8"
testing <- read.csv(file = "Corona_NLP_test.csv", header = TRUE, sep = ",", stringsAsFactors = FALSE, strip.white = TRUE, encoding = "latin1")
Data
Exploration
Training data
set
Displaying the structure of the
Training data set:
'data.frame': 41157 obs. of 6 variables:
$ UserName : int 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 ...
$ ScreenName : int 48751 48752 48753 48754 48755 48756 48757 48758 48759 48760 ...
$ Location : chr "London" "UK" "Vagabonds" "" ...
$ TweetAt : chr "16-03-2020" "16-03-2020" "16-03-2020" "16-03-2020" ...
$ OriginalTweet: chr "@MeNyrbie @Phil_Gahan @Chrisitv https://t.co/iFz9FAn2Pa and https://t.co/xX6ghGFzCC and https://t.co/I2NlzdxNo8" "advice Talk to your neighbours family to exchange phone numbers create contact list with phone numbers of neigh"| __truncated__ "Coronavirus Australia: Woolworths to give elderly, disabled dedicated shopping hours amid COVID-19 outbreak htt"| __truncated__ "My food stock is not the only one which is empty...\n\n\n\n\n\nPLEASE, don't panic, THERE WILL BE ENOUGH FOOD F"| __truncated__ ...
$ Sentiment : chr "Neutral" "Positive" "Positive" "Positive" ...
Identifying missing (NAs)
values in the Training data set:
UserName ScreenName Location TweetAt OriginalTweet Sentiment
0 0 0 0 0 0
Based on the
frequency table, there are no missing values (NAs) in
the Training data frame.
Displaying the content of
the first two observations of the OriginalTweet variable
within the Training data set:
[1] "@MeNyrbie @Phil_Gahan @Chrisitv https://t.co/iFz9FAn2Pa and https://t.co/xX6ghGFzCC and https://t.co/I2NlzdxNo8"
[1] "advice Talk to your neighbours family to exchange phone numbers create contact list with phone numbers of neighbours schools employer chemist GP set up online shopping accounts if poss adequate supplies of regular meds but not over order"
Displaying the frequency
and the distribution of the Sentiment variable within the
Training data set:
Extremely Negative Extremely Positive Negative Neutral Positive
5481 6624 9917 7713 11422


Testing data
set
Displaying the structure of the
Testing data set:
'data.frame': 3798 obs. of 6 variables:
$ UserName : int 1 2 3 4 5 6 7 8 9 10 ...
$ ScreenName : int 44953 44954 44955 44956 44957 44958 44959 44960 44961 44962 ...
$ Location : chr "NYC" "Seattle, WA" "" "Chicagoland" ...
$ TweetAt : chr "02-03-2020" "02-03-2020" "02-03-2020" "02-03-2020" ...
$ OriginalTweet: chr "TRENDING: New Yorkers encounter empty supermarket shelves (pictured, Wegmans in Brooklyn), sold-out online groc"| __truncated__ "When I couldn't find hand sanitizer at Fred Meyer, I turned to #Amazon. But $114.97 for a 2 pack of Purell??!!C"| __truncated__ "Find out how you can protect yourself and loved ones from #coronavirus. ?" "#Panic buying hits #NewYork City as anxious shoppers stock up on food&medical supplies after #healthcare wo"| __truncated__ ...
$ Sentiment : chr "Extremely Negative" "Positive" "Extremely Positive" "Negative" ...
Identifying missing (NAs)
values in the Testing data set:
UserName ScreenName Location TweetAt OriginalTweet Sentiment
0 0 0 0 0 0
Based on the
frequency table, there are also no missing values (NAs)
in the Testing data frame.
Displaying the content of
the first two observations of the OriginalTweet variable
within the Testing data set:
[1] "TRENDING: New Yorkers encounter empty supermarket shelves (pictured, Wegmans in Brooklyn), sold-out online grocers (FoodKick, MaxDelivery) as #coronavirus-fearing shoppers stock up https://t.co/Gr76pcrLWh https://t.co/ivMKMsqdT1"
[1] "When I couldn't find hand sanitizer at Fred Meyer, I turned to #Amazon. But $114.97 for a 2 pack of Purell??!!Check out how #coronavirus concerns are driving up prices. https://t.co/ygbipBflMY"
Displaying the frequency
and the distribution of the Sentiment variable within the
Testing data set:
Extremely Negative Extremely Positive Negative Neutral Positive
592 599 1041 619 947


Data
Preprocessing
Training data
set
Replacing
the entries labeled as Extremely Positive with Positive
and the entries labeled as Extremely Negative with
Negative of the Sentiment variable in the
Training data set:
training$Sentiment[training$Sentiment == "Extremely Positive"] <- "Positive"
training$Sentiment[training$Sentiment == "Extremely Negative"] <- "Negative"
Displaying the frequency
and the distribution of the Sentiment variable within the
Training data set:
Negative Neutral Positive
15398 7713 18046


Factorizing the
Sentiment variable, assigning numeric values to the resulting
factors, and adding them to the Training data set as a new column
named Labels:
training["Labels"] <- as.integer(as.factor(training$Sentiment)) - 1
Displaying the frequency
of the Labels variable within the Training data
set:
0 1 2
15398 7713 18046
The frequency
counts of the Labels variable exactly match those of
the frequency of the Sentiment column in the
Training data set..
Cleaning and transforming
the text of the OriginalTweet variable in the
Training data set:
training$OriginalTweet <- replace_non_ascii(training$OriginalTweet)
training$OriginalTweet <- tolower(training$OriginalTweet)
training$OriginalTweet <- replace_date(training$OriginalTweet)
training$OriginalTweet <- replace_time(training$OriginalTweet)
training$OriginalTweet <- replace_money(training$OriginalTweet)
training$OriginalTweet <- replace_number(training$OriginalTweet)
training$OriginalTweet <- replace_contraction(training$OriginalTweet, ignore.case = TRUE)
training$OriginalTweet <- replace_grade(training$OriginalTweet)
training$OriginalTweet <- replace_email(training$OriginalTweet)
training$OriginalTweet <- replace_hash(training$OriginalTweet)
training$OriginalTweet <- replace_tag(training$OriginalTweet)
training$OriginalTweet <- replace_html(training$OriginalTweet)
training$OriginalTweet <- replace_url(training$OriginalTweet)
training$OriginalTweet <- replace_internet_slang(training$OriginalTweet, ignore.case = TRUE)
training$OriginalTweet <- replace_emoji(training$OriginalTweet)
training$OriginalTweet <- replace_emoticon(training$OriginalTweet)
training$OriginalTweet <- removeWords(training$OriginalTweet, stopwords("english"))
training$OriginalTweet <- replace_symbol(training$OriginalTweet)
training$OriginalTweet <- mgsub(training$OriginalTweet, "'", "")
training$OriginalTweet <- strip(training$OriginalTweet)
training$OriginalTweet <- replace_kern(training$OriginalTweet)
training$OriginalTweet <- wordStem(training$OriginalTweet, language = "english")
training$OriginalTweet <- replace_white(training$OriginalTweet)
training <- training[!(training$OriginalTweet== ""), ]
Setting up a Vector
Source to treat each element of the OriginalTweet variable
in the Training data set as individual
documents:
training.vs <- VectorSource(training$OriginalTweet)
Displaying the structure
of the Training vector source:
Classes 'VectorSource', 'SimpleSource', 'Source' hidden list of 5
$ encoding: chr ""
$ length : int 41119
$ position: num 0
$ reader :function (elem, language, id)
$ content : chr [1:41119] "advice talk neighbours family exchange phone numbers create contact list phone numbers neighbours schools emplo"| __truncated__ "coronavirus australia woolworths give elderly disabled dedicated shopping hours amid covid outbreak" "food stock one empty please panic will enough food everyone take need stay calm stay saf" "ready go supermarket outbreak i paranoid food stock litteraly empty serious thing please panic causes shortag" ...
Creating a Volatile
Corpus from the Training vector source:
training.vc <- VCorpus(training.vs)
Displaying details about
the Volatile Corpus:
<<VCorpus>>
Metadata: corpus specific: 0, document level (indexed): 0
Content: documents: 41119
Displaying details of the
first two documents within the Training Volatile
Corpus:
[[1]]
<<PlainTextDocument>>
Metadata: 7
Content: chars: 194
[[2]]
<<PlainTextDocument>>
Metadata: 7
Content: chars: 99
Displaying the content of
the first two documents within the Training Volatile
Corpus:
[1] "advice talk neighbours family exchange phone numbers create contact list phone numbers neighbours schools employer chemist gp set online shopping accounts poss adequate supplies regular meds ord"
[1] "coronavirus australia woolworths give elderly disabled dedicated shopping hours amid covid outbreak"
Displaying a
Wordcloud of the top 100 most frequent
words:

Displaying a list of the
top 10 most frequent words:
Displaying a
Wordcloud of the top 100 most frequent words of the
positive sentiments:

Displaying a list of the
top 10 most frequent words of the positive
sentiments:
Generating a
Document-Term Matrix from the Training Volatile Corpus to
depict the frequency of terms within each document in the
collection:
dtm <- DocumentTermMatrix(training.vc)
Inspecting the contents of
the Document-Term Matrix and displaying it in a human-readable format.
This displays terms and their frequencies within each document in the
collection:
tm::inspect(dtm)
<<DocumentTermMatrix (documents: 41119, terms: 37869)>>
Non-/sparse entries: 638798/1556496613
Sparsity : 100%
Maximal term length: 127
Weighting : term frequency (tf)
Sample :
Terms
Docs can consumer covid food grocery people prices store supermarket will
18898 0 0 0 0 0 0 1 0 0 1
26959 0 0 0 0 0 1 1 0 0 0
28881 0 0 1 0 0 0 1 0 0 0
31912 0 0 1 0 0 0 1 0 0 0
32027 0 0 1 0 0 0 1 0 0 0
32028 0 0 1 0 0 0 1 0 0 0
33965 0 0 1 1 0 0 0 0 0 0
34261 0 0 0 0 0 0 0 0 0 0
37744 0 0 0 0 0 0 0 0 0 0
9770 0 0 0 0 0 0 1 0 0 0
Showing the number of
terms that are repeated 100 times or more in the Document-Term
Matrix from the Training data set:
# Gets a list of those terms repeated 100 times or more from the Document-Term Matrix:
high.freq.terms <- findFreqTerms(dtm, lowfreq = 100)
# Display the quantity of those terms repeated 100 times or more:
length(high.freq.terms)
[1] 1121
Displaying a list of terms
repeated 100 times or more in the Document-Term Matrix from the
Training data set:
Showing the number of
terms that are repeated less than 100 times in the Document-Term
Matrix from the Training data set:
[1] 36748
Displaying a list of terms
repeated less 100 times (with a low frequency of 90) in the
Document-Term Matrix from the Training data
set:
Removing those terms
repeated less than 100 times from the Document-Term Matrix from the
Training data set:
dtm <- dtm[, colnames(dtm) %in% high.freq.terms]
Confirming there are no
terms repeated less than 100 times in the Document-Term Matrix
from the Training data set:
cat("Terms repeated less than 100 times: ", length(findFreqTerms(dtm, highfreq = 99)))
Terms repeated less than 100 times: 0
Testing data
set
Replacing
the entries labeled as Extremely Positive with Positive
and the entries labeled as Extremely Negative with
Negative of the Sentiment variable in the Testing
data set:
testing$Sentiment[testing$Sentiment == "Extremely Positive"] <- "Positive"
testing$Sentiment[testing$Sentiment == "Extremely Negative"] <- "Negative"
Displaying the frequency
and the distribution of the Sentiment variable within the
Testing data set:
Negative Neutral Positive
1633 619 1546


Factorizing the
Sentiment variable, assigning numeric values to the resulting
factors, and adding them to the Testing data set as a new column
named Labels:
testing["Labels"] <- as.integer(as.factor(testing$Sentiment)) - 1
Displaying the frequency
of the Labels variable within the Testing data
set:
0 1 2
1633 619 1546
The frequency
counts of the Labels variable exactly match those of
the frequency of the Sentiment column in the
Testing data set.
Cleaning and transforming
the text of the OriginalTweet variable in the
Testing data set:
testing$OriginalTweet <- replace_non_ascii(testing$OriginalTweet)
testing$OriginalTweet <- tolower(testing$OriginalTweet)
testing$OriginalTweet <- replace_date(testing$OriginalTweet)
testing$OriginalTweet <- replace_time(testing$OriginalTweet)
testing$OriginalTweet <- replace_money(testing$OriginalTweet)
testing$OriginalTweet <- replace_number(testing$OriginalTweet)
testing$OriginalTweet <- replace_contraction(testing$OriginalTweet, ignore.case = TRUE)
testing$OriginalTweet <- replace_grade(testing$OriginalTweet)
testing$OriginalTweet <- replace_email(testing$OriginalTweet)
testing$OriginalTweet <- replace_hash(testing$OriginalTweet)
testing$OriginalTweet <- replace_tag(testing$OriginalTweet)
testing$OriginalTweet <- replace_html(testing$OriginalTweet)
testing$OriginalTweet <- replace_url(testing$OriginalTweet)
testing$OriginalTweet <- replace_internet_slang(testing$OriginalTweet, ignore.case = TRUE)
testing$OriginalTweet <- replace_emoji(testing$OriginalTweet)
testing$OriginalTweet <- replace_emoticon(testing$OriginalTweet)
testing$OriginalTweet <- removeWords(testing$OriginalTweet, stopwords("english"))
testing$OriginalTweet <- replace_symbol(testing$OriginalTweet)
testing$OriginalTweet <- mgsub(testing$OriginalTweet, "'", "")
testing$OriginalTweet <- strip(testing$OriginalTweet)
testing$OriginalTweet <- replace_kern(testing$OriginalTweet)
testing$OriginalTweet <- wordStem(testing$OriginalTweet, language = "english")
testing$OriginalTweet <- replace_white(testing$OriginalTweet)
testing <- testing[!(testing$OriginalTweet== ""), ]
Setting up a Vector
Source to treat each element of the OriginalTweet variable
in the Testing data set as individual
documents:
testing.vs <- VectorSource(testing$OriginalTweet)
Creating a Volatile
Corpus from the Testing vector source:
testing.vc <- VCorpus(testing.vs)
Generating a
Document-Term Matrix utilizing the Training Document-Term
Matrix and the Testing Volatile Corpus. This process ensures that
the terms found in the Training Document-Term Matrix are mirrored
in the Testing Document-Term Matrix:
test_dtm <- DocumentTermMatrix(testing.vc, control = list(dictionary = Terms(dtm)))
Showing the count of
documents and terms in both Document-Term Matrices (number of terms
should be the same):
DTM Documents Terms
[Training] 41119 1121
[Testing] 3797 1121
>>> The number of terms are the same!!!!!
Presenting the lists of
terms contained within both Document-Term Matrices (the terms should be
the same):
>>> The terms are identical!!!!!
Model Training and
Evaluation.:
Training a
Multinomial Naive Bayes model on the training data:
# Train the Naïve Bayes model on the training data,
multinomial.naive.bayes.model <- multinomial_naive_bayes(as.matrix(dtm), as.factor(training$Labels), laplace = 1)
Getting the
predictions of the model on the testing data:
# Getting the predictions of the Naïve model on the validation data.
multinomial.naive.bayes.predictions <- predict(multinomial.naive.bayes.model, newdata = as.matrix(test_dtm))
Displaying the
accuracy of the model:
Accuracy: 64.52%
Showing the count of the
incorrect predictions labels of the model:
Amount of incorrect predictions: 1347
Displaying a list of the
actual labels next to incorrect predictions labels of the
model:
Presenting a frequency
table of the actual labels of the Testing data
set:
Actual labels table:
0 1 2
1633 618 1546
Showing a frequency table
of the predictions labels of the model:
Predictions labels table:
multinomial.naive.bayes.predictions
0 1 2
1613 602 1582
Displaying a Confusion
Matrix of the actual labels of the Testing data set vs
the predictions labels of the model:
Confusion Matrix:
multinomial.naive.bayes.predictions
(Pred Neg) 0 (Pred Neu) 1 (Pred Pos) 2
(True Neg) 0 1106 194 333
(True Neu) 1 181 266 171
(True Pos) 2 326 142 1078
Presenting a Proportion
Confusion Matrix comparing the total count of the actual
labels from the Testing data set against the predicted
labels generated by the model.:
Proportion Confusion Matrix:
multinomial.naive.bayes.predictions
(Pred Neg) 0 (Pred Neu) 1 (Pred Pos) 2
(True Neg) 0 0.29128259 0.05109297 0.08770082
(True Neu) 1 0.04766921 0.07005531 0.04503555
(True Pos) 2 0.08585726 0.03739795 0.28390835
Based on the
Confusion Matrices, 2450 of the predictions were
correctly labeled, accounting for
64.52% of all predictions. These findings corroborate
previous data from this study. Subtracting 2450 from the total
predictions made (3797) yields 1347 (the number of incorrect predictions
calculated previously), and the percentage obtained from the Confusion
Matrices precisely matches the accuracy percentage of the model (without
rounding).
Of the incorrectly predicted values, it appears
that the model mislabeled more Negative values
as Positive and vice versa. Specifically, 333 Negative values
were labeled as Positive, constituting approximately 8.77% of all
predictions. This was closely followed by 326 Positive values labeled as
Negative, representing around 8.59% of all predictions.
Note: Use the following table
for the Confusion Matrices interpretation.
True-Negative False-Neutral False-Positive
False-Negative True-Neutral False-Positive
False-Negative False-Neutral True-Positive
LS0tCnRpdGxlOiA8Zm9udCBjb2xvcj0iYmxhY2siPlRleHQgQ2xhc3NpZmljYXRpb24gYW5kIFNlbnRpbWVudCBBbmFseXNpczwvZm9udD4KYXV0aG9yOiAiQXV0aG9yZWQgYnkgPHN0cm9uZz5FbG95IEFsdmluIEx1bmE8L3N0cm9uZz4iCmRhdGU6ICJDcmVhdGVkIG9uOiBKYW51YXJ5IDI2LCAyMDI0IC0gTGFzdCB1cGRhdGVkIG9uOiBNYXJjaCA3LCAyMDI0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgRm9yIHRoZSAzRCBFeHBsb2RlZCBQaWUgQ2hhcnQ6CmlmICghcmVxdWlyZU5hbWVzcGFjZSgicGxvdHJpeCIsIHF1aWV0bHkgPSBUUlVFKSkgewogIGluc3RhbGwucGFja2FnZXMoInBsb3RyaXgiKQp9CgojIEZvciBzdHJfZXh0cmFjdF9hbGw6CmlmICghcmVxdWlyZU5hbWVzcGFjZSgic3RyaW5nciIsIHF1aWV0bHkgPSBUUlVFKSkgewogIGluc3RhbGwucGFja2FnZXMoInN0cmluZ3IiKQp9CgojIEEgZGVwZW5kZW5jeSBvZiB0aGUgd29yZGNsb3VkczoKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJSQ29sb3JCcmV3ZXIiLCBxdWlldGx5ID0gVFJVRSkpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKQp9CgojIFRvIGNyZWF0ZSB0aGUgd29yZGNsb3VkczoKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJ3b3JkY2xvdWQiLCBxdWlldGx5ID0gVFJVRSkpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJ3b3JkY2xvdWQiKQp9CgojIEZvciB3b3JkU3RlbSgpIC0gc3RlbW1pbmcgdHJhbnNmb3JtYXRpb24gZm9yIFRleHQgTWluaW5nOgojIGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9Tbm93YmFsbEMvdmVyc2lvbnMvMC43LjEvdG9waWNzL3dvcmRTdGVtCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiU25vd2JhbGxDIiwgcXVpZXRseSA9IFRSVUUpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiU25vd2JhbGxDIikKfQoKIyBGb3IgcmVwbGFjZV9ub25fYXNjaWkoKQojIGh0dHBzOi8vZ2l0aHViLmNvbS90cmlua2VyL3RleHRjbGVhbgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoInRleHRjbGVhbiIsIHF1aWV0bHkgPSBUUlVFKSkgewogIGluc3RhbGwucGFja2FnZXMoInRleHRjbGVhbiIpCn0KCiMgRm9yIGNoZWNrX3RleHQoKQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoImh1bnNwZWxsIiwgcXVpZXRseSA9IFRSVUUpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiaHVuc3BlbGwiKQp9CgojIE5hdHVyYWwgTGFuZ3VhZ2UgUHJvY2Vzc2luZzogUmVxdWlyZW1lbnQgb2YgdG06CmlmICghcmVxdWlyZU5hbWVzcGFjZSgiTkxQIiwgcXVpZXRseSA9IFRSVUUpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiTkxQIikKfQoKIyBUZXh0IE1pbmluZzogRm9yIFZlY3RvclNvdXJjZSgpLCBWQ29ycHVzKCksIGFuZCBEb2N1bWVudFRlcm1NYXRyaXgoKToKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJ0bSIsIHF1aWV0bHkgPSBUUlVFKSkgewogIGluc3RhbGwucGFja2FnZXMoInRtIikKfQoKIyBGb3IgTXVsdGlub21pYWwgTmFpdmUgQmF5ZXMKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJuYWl2ZWJheWVzIiwgcXVpZXRseSA9IFRSVUUpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygibmFpdmViYXllcyIpCn0KYGBgCgo8YnI+Cjxicj4KPGZvbnQgY29sb3I9InJlZCI+PHN0cm9uZz5Ob3RlOiA8L3N0cm9uZz5Tb21lIG9mIHRoZSBjb2RlIGhhcyBiZWVuIG9taXR0ZWQgdG8gZW5oYW5jZSByZWFkYWJpbGl0eS48L2ZvbnQ+Cgo8ZGl2IHN0eWxlPSJjb2xvcjpibGFjaztiYWNrZ3JvdW5kLWNvbG9yOmxpZ2h0eWVsbG93Ij4KICAgPGZvbnQgc2l6ZT0iMiI+PHNwYW4gc3R5bGU9ImNvbG9yOiBkYXJrYmx1ZSI+VGhlIGZvbGxvd2luZyB0ZXJtcyBtaWdodCBiZSB1c2VkIGludGVyY2hhbmdlYWJseSB3aXRoIGVhY2ggb3RoZXI6PC9zcGFuPjwvZm9udD4KICAgPGJyPgogICA8YnI+CiAgIDxmb250IHNpemU9IjIiPjxzcGFuIHN0eWxlPSJjb2xvcjogZGFya2JsdWUiPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOzxzdHJvbmc+Um93czwvc3Ryb25nPiA9IE9ic2VydmF0aW9ucyA9IFJlY29yZHM8L3NwYW4+PC9mb250PgogICA8YnI+CiAgIDxmb250IHNpemU9IjIiPjxzcGFuIHN0eWxlPSJjb2xvcjogZGFya2JsdWUiPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOzxzdHJvbmc+Q29sdW1uczwvc3Ryb25nPiA9IFZhcmlhYmxlcyA9IEZlYXR1cmVzPC9zcGFuPjwvZm9udD4KPC9kaXY+Cjxicj4KPGJyPgo8Zm9udCBzaXplPSIrMiIgY29sb3I9Im5hdnkiPjxzdHJvbmc+UHVycG9zZSBhbmQgT2JqZWN0aXZlczo8L3N0cm9uZz48L3NwYW4+PC9mb250Pgo8YnI+CjxwPlRoZSBwdXJwb3NlIG9mIHRoaXMgcHJvamVjdCBpcyB0byBzaG93Y2FzZSBteSBrbm93bGVkZ2UgaW4gPHN0cm9uZz5EYXRhIEFuYWx5dGljczwvc3Ryb25nPiwgZm9jdXNpbmcgb24gdGhlIGFwcGxpY2F0aW9uIG9mIG1hY2hpbmUgbGVhcm5pbmcgdGVjaG5pcXVlcyBmb3IgPHN0cm9uZz50ZXh0IGNsYXNzaWZpY2F0aW9uPC9zdHJvbmc+LiBNeSBvYmplY3RpdmUgaXMgdG8gYXR0ZW1wdCA8c3Ryb25nPnByZWRpY3RpbmcgdGhlIHNlbnRpbWVudDwvc3Ryb25nPiDigJRwb3NpdGl2ZSwgbmV1dHJhbCwgb3IgbmVnYXRpdmXigJQgb2YgaW5kaXZpZHVhbHMgYmFzZWQgb24gdGhlaXIgVHdpdHRlciBtZXNzYWdlcyBpbiByZWdhcmRzIHRvIENPVklELTE5LCB1c2luZyB0aG9zZSB3b3JkcyB0aGF0IGdldCByZXBlYXRlZCA8c3Ryb25nPjEwMCB0aW1lcyBvciBtb3JlPC9zdHJvbmc+LiBUaGUgbW9kZWwgdGhhdCB3aWxsIGJlIHVzZWQgaGVyZSBpcyB0aGUgPHN0cm9uZz5NdWx0aW5vbWlhbCBOYWl2ZSBCYXllczwvc3Ryb25nPi48L3A+Cjxicj4KPGJyPgo8Zm9udCBzaXplPSIrMiI+PHNwYW4gc3R5bGU9ImNvbG9yOiBuYXZ5OyI+PHN0cm9uZz5EYXRhIENvbGxlY3Rpb248L3N0cm9uZz48L3NwYW4+PC9mb250Pgo8YnI+Cjx1bD4KICAgPGxpPlRoZSBkYXRhIHdhcyBvYnRhaW5lZCBmcm9tIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvZGF0YXRhdHRsZS9jb3ZpZC0xOS1ubHAtdGV4dC1jbGFzc2lmaWNhdGlvbj9yZXNvdXJjZT1kb3dubG9hZCBvbiBKYW51YXJ5LzI2LzIwMjQuPC9saT4KICAgPGxpPlR3byBmaWxlcyB3ZXJlIGNvbGxlY3RlZCB3aXRoIHRoZSBuYW1lczogIkNvcm9uYV9OTFBfdHJhaW4uY3N2IiBhbmQgIkNvcm9uYV9OTFBfdGVzdC5jc3YiPC9saT4KICAgPGxpPlRoZSBmaWxlcyBhcmUgaW4gdGhlIDxzdHJvbmc+Y29tbWEtc2VwYXJhdGVkIHZhbHVlcyAoY3N2KTwvc3Ryb25nPiBmb3JtYXQuCjwvdWw+Cjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5Mb2FkaW5nIHRoZSBkYXRhOjwvc3Ryb25nPjwvZm9udD4KCjwhLS0gSW4gdGhpcyBhcmVhLCBJJ20gdXNpbmcgdGhlIHZhcmlhYmxlIG5hbWVzICJ0cmFpbmluZyIgYW5kICJ0ZXN0aW5nIiB0byBob2xkIHRoZSBsb2FkZWQgZGF0YSBvZiB0aGUgdG8gZGF0YSBzZXQgaW4gdHdvIGRhdGEgZnJhbWVzLiBUaGVzZSB0d28gbmFtZXMgd2lsbCBiZSB1c2VkIGZvciBkaXNwbGF5aW5nIHB1cnBvc2VzLCBidXQgb3RoZXIgaW50ZXJuYWwgbmFtZXMgd2lsbCBiZSB1c2VkIHRocm91Z2hvdXQgdGhlIGNvZGluZyBkbyB0byBwcm9jZXNzZXMgbm90IG1lYW50IHRvIGJlIHNlZWluZyBieSB0aGUgdmlld2VycyBvZiB0aGUgaHRtbCBmaWxlLiAtLT4KCjwhLS0gVXNlIExhdGluLTEgKCJsYXRpbjEiKSwgYWxzbyBjYWxsZWQgSVNPLTg4NTktMSwgYW4gOC1iaXQgY2hhcmFjdGVyIHNldCBlbmRvcnNlZCBieSB0aGUgSW50ZXJuYXRpb25hbCBPcmdhbml6YXRpb24gZm9yIFN0YW5kYXJkaXphdGlvbiAoSVNPKSB0byByZXByZXNlbnQgdGhlIGFscGhhYmV0cyBvZiBXZXN0ZXJuIEV1cm9wZWFuIGxhbmd1YWdlcy4gSVNPIExhdGluIDEgd2FzIGRlc2lnbmVkIHdpdGggdGhlIGZvbGxvd2luZyBsYW5ndWFnZXMgaW4gbWluZDogRGFuaXNoLCBEdXRjaCwgRW5nbGlzaCwgRmFlcm9lc2UsIEZpbm5pc2gsIEZyZW5jaCwgR2VybWFuLCBJY2VsYW5kaWMsIElyaXNoLCBJdGFsaWFuLCBOb3J3ZWdpYW4sIFBvcnR1Z3Vlc2UsIFNwYW5pc2ggYW5kIFN3ZWRpc2guLS0+Cgo8IS0tIFVzZSBVVEYtOCAoIlVURi04IiksIFVuaWNvZGUgVHJhbnNmb3JtYXRpb24gRm9ybWF0LTgsIHRvIHN1cHBvcnQgYWxsIGxhbmd1YWdlcyBhbmQgYWxwaGFiZXRzLCBpbmNsdWRpbmcgQXNpYW4gbGFuZ3VhZ2VzIGFuZCB0aGVpciBjaGFyYWN0ZXIgZGVwdGguIEl0IGlzIGEgd2lkZWx5IHN1cHBvcnRlZCBhbmQgZmxleGlibGUgY2hhcmFjdGVyIGVuY29kaW5nLiBVVEYtOCBpcyBjYXBhYmxlIG9mIGVuY29kaW5nIGFsbCAxLDExMiwwNjQgdmFsaWQgVW5pY29kZSBjb2RlIHBvaW50cyB1c2luZyBvbmUgdG8gZm91ciBvbmUtYnl0ZSAoOC1iaXQpIGNvZGUgdW5pdHMuIC0tPgoKPCEtLSBVbmljb2RlIGlzIGFuIGludGVybmF0aW9uYWwgY2hhcmFjdGVyIGVuY29kaW5nIHN0YW5kYXJkIHRoYXQgcHJvdmlkZXMgYSB1bmlxdWUgbnVtYmVyIGZvciBldmVyeSBjaGFyYWN0ZXIgYWNyb3NzIGxhbmd1YWdlcyBhbmQgc2NyaXB0cywgbWFraW5nIGFsbW9zdCBhbGwgY2hhcmFjdGVycyBhY2Nlc3NpYmxlIGFjcm9zcyBwbGF0Zm9ybXMsIHByb2dyYW1zLCBhbmQgZGV2aWNlcy4gLS0+CmBgYHtyfQp0cmFpbmluZyA8LSByZWFkLmNzdihmaWxlID0gIkNvcm9uYV9OTFBfdHJhaW4uY3N2IiwgaGVhZGVyID0gVFJVRSwgc2VwID0gIiwiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIHN0cmlwLndoaXRlID0gVFJVRSwgZW5jb2RpbmcgPSAibGF0aW4xIikKCiNlbmNvZGluZyA9ICJVVEYtOCIKdGVzdGluZyA8LSByZWFkLmNzdihmaWxlID0gIkNvcm9uYV9OTFBfdGVzdC5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwgc3RyaXAud2hpdGUgPSBUUlVFLCBlbmNvZGluZyA9ICJsYXRpbjEiKQpgYGAKPCEtLSBGaXJzdCBzdWJzdGl0dXRpb24gb2YgdGhlIGRhdGEgZnJhbWVzJyBuYW1lcy4gLS0+CmBgYHtyIGVjaG8gPSBGQUxTRX0KZGYudHJhaW4ucmF3IDwtIHRyYWluaW5nCmRmLnRlc3QucmF3IDwtIHRlc3RpbmcKYGBgCjxicj4KPGZvbnQgc2l6ZT0iKzIiPjxzcGFuIHN0eWxlPSJjb2xvcjogbmF2eTsiPjxzdHJvbmc+RGF0YSBFeHBsb3JhdGlvbjwvc3Ryb25nPjwvc3Bhbj48L2ZvbnQ+Cjxicj4KPGJyPgo8Zm9udCBzaXplPSIrMSIgY29sb3I9Im1hZ2VudGEiPjxzdHJvbmc+VHJhaW5pbmcgZGF0YSBzZXQ8L3N0cm9uZz48L2ZvbnQ+Cjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIDx1PlRyYWluaW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRX0Kc3RyKGRmLnRyYWluLnJhdykKYGBgCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5JZGVudGlmeWluZyBtaXNzaW5nIChOQXMpIHZhbHVlcyBpbiB0aGUgPHU+VHJhaW5pbmc8L3U+IGRhdGEgc2V0Ojwvc3Ryb25nPjwvZm9udD4KYGBge3IgZWNobyA9IEZBTFNFfQpjb2xTdW1zKGlzLm5hKGRmLnRyYWluLnJhdykpCmBgYAoKPGRpdiBzdHlsZT0iY29sb3I6YmxhY2s7YmFja2dyb3VuZC1jb2xvcjpsaWdodHllbGxvdyI+CiAgIDxicj4KICAgPGZvbnQgc2l6ZT0iKzAuMyI+PHNwYW4gc3R5bGU9ImNvbG9yOiBkYXJrYmx1ZSI+QmFzZWQgb24gdGhlIGZyZXF1ZW5jeSB0YWJsZSwgdGhlcmUgYXJlIDxzdHJvbmc+bm88L3N0cm9uZz4gbWlzc2luZyB2YWx1ZXMgKE5BcykgaW4gdGhlIDxzdHJvbmc+VHJhaW5pbmc8L3N0cm9uZz4gZGF0YSBmcmFtZS48L3NwYW4+PC9mb250PgogICA8YnI+CiAgIDxicj4KPC9kaXY+Cgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+RGlzcGxheWluZyB0aGUgY29udGVudCBvZiB0aGUgPHU+Zmlyc3QgdHdvIG9ic2VydmF0aW9uczwvdT4gb2YgdGhlIDxlbT5PcmlnaW5hbFR3ZWV0PC9lbT4gdmFyaWFibGUgd2l0aGluIHRoZSA8dT5UcmFpbmluZzwvdT4gZGF0YSBzZXQ6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CmRmLnRyYWluLnJhdyRPcmlnaW5hbFR3ZWV0W1sxXV0KYGBgCmBgYHtyIGVjaG8gPSBGQUxTRX0KZGYudHJhaW4ucmF3JE9yaWdpbmFsVHdlZXRbWzJdXQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIHRoZSBmcmVxdWVuY3kgYW5kIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIDxlbT5TZW50aW1lbnQ8L2VtPiB2YXJpYWJsZSB3aXRoaW4gdGhlIDx1PlRyYWluaW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBUaGUgZnJlcXVlbmN5IHRhYmxlIG9mIHRoZSBTZW50aW1lbnQgZmVhdHVyZSBpbiB0aGUgZGYudHJhaW4ucmF3IGRhdGEgZnJhbWUuCnRibC5yYXcgPC0gdGFibGUoZGYudHJhaW4ucmF3JFNlbnRpbWVudCkKdGJsLnJhdwpgYGAKPCEtLSAKQWx0aG91Z2ggSGlzdG9ncmFtcyBhcmUgbW9zdCBjb21tb25seSB1c2VkIGZvciB2aXN1YWxpemluZyB0aGUgZGlzdHJpYnV0aW9uLCB0aGV5IGFyZSBiZXR0ZXIgdXNlZCBmb3IgY29udGludW91cyBudW1lcmljYWwgZGF0YS4gRm9yIGNhdGVnb3JpY2FsIGRhdGEsIGJhciBwbG90cyBhcmUgbW9yZSBhcHByb3ByaWF0ZS4KLS0+CjwhLS0gaHR0cHM6Ly9yLWdyYXBoLWdhbGxlcnkuY29tLzIwOS10aGUtb3B0aW9ucy1vZi1iYXJwbG90Lmh0bWwgLS0+CmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBDYXRlZ29yeSBuYW1lcyAobGFiZWxzKToKbm1zIDwtIGMoIkV4dG0uIE4uIiwgIkV4dG0uIFAuIiwgIk5lZy4iLCAiTmV1dC4iLCAiUG9zLiIpCiMgQ2F0ZWdvcnkgY29sb3JzOgpjbHJzIDwtIGMoInJlZCIsICJibHVlIiwgInBpbmsiLCAid2hpdGUiLCAibGlnaHRibHVlMiIpCgojIENyZWF0aW9uIG9mIHRoZSBiYXIgcGxvdCB3aXRoIGNvbG9ycyBhbmQgY3VzdG9taXplZCBiYXIgd2lkdGg6CmJhcnBsb3QodGJsLnJhdywgbmFtZXMuYXJnID0gbm1zLCBtYWluID0gIlNlbnRpbWVudCdzIGRpc3RyaWJ1dGlvbiBpbiB0aGUgVHJhaW5pbmcgZGF0YSBzZXRcbihmcmVxdWVuY3kpIiwgY29sID0gY2xycywgd2lkdGggPSBjKDAuNzUsIDAuODUsIDEuNSwgMS4yLCAxLjcpLCB4bGFiID0gIkNhdGVnb3JpZXMiLCB5bGFiID0gIkZyZXF1ZW5jeSIsIGZvbnQubGFiID0gMywgY29sLmxhYiA9ICJibHVlIikKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgQ2F0ZWdvcnkgbmFtZXMgKGxhYmVscyk6Cm5hbWVzIDwtIGMoIkV4dG0uIE5lZy4iLCAiRXh0bS4gUG9zLiIsICJOZWcuIiwgIk5ldXQuIiwgIlBvcy4iKQojIENhdGVnb3J5IHBlcmNlbnRhZ2VzOgpwZXJjZW50YWdlIDwtIHJvdW5kKHRibC5yYXcgLyBsZW5ndGgoZGYudHJhaW4ucmF3JFNlbnRpbWVudCkgKiAxMDAsIDIpCiMgQWRkaW5nIHRoZSBmaXJzdCBwYXJlbnRoZXNpcyB0byB0aGUgbGFiZWxzOgpsYmxzIDwtIHBhc3RlKCIoIiwgbmFtZXMsIHNlcCA9ICIiKQojIEFkZGluZyB0aGUgc2Vjb25kIHBhcmVudGhlc2lzIGFuZCB0aGUgcGVyY2VudGFnZXMgdG8gbGFiZWxzOgpsYmxzIDwtIHBhc3RlKGxibHMsIHBlcmNlbnRhZ2UsIHNlcCA9ICIpICIpCiMgQWRkaW5nIHRoZSAlIHN5bWJvbHMgdG8gbGFiZWxzCmxibHMgPC0gcGFzdGUobGJscywiJSIsc2VwID0gIiIpCgojIENyZWF0aW5nIHRoZSBwaWUgY2hhcnQgd2l0aCB0aGUgbGFiZWxzIGFuZCBwZXJjZW50YWdlcywgYW5kIHdpdGggdGhlIHNhbWUgY29sb3JzIGFzIGluIHRoZSBiYXJwbG90LgpwaWUodGJsLnJhdywgbWFpbiA9ICJTZW50aW1lbnQncyBkaXN0cmlidXRpb24gaW4gdGhlIFRyYWluaW5nIGRhdGEgc2V0XG4ocGVyY2VudGFnZSkiLCBsYWJlbHMgPSBsYmxzLCBjb2wgPSBjKCJyZWQiLCAiYmx1ZSIsICJwaW5rIiwgIndoaXRlIiwgImxpZ2h0Ymx1ZTIiKSkKYGBgCjxmb250IHNpemU9IisxIiBjb2xvcj0ibWFnZW50YSI+PHN0cm9uZz5UZXN0aW5nIGRhdGEgc2V0PC9zdHJvbmc+PC9mb250Pgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+RGlzcGxheWluZyB0aGUgc3RydWN0dXJlIG9mIHRoZSA8dT5UZXN0aW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRX0Kc3RyKGRmLnRlc3QucmF3KQpgYGAKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPklkZW50aWZ5aW5nIG1pc3NpbmcgKE5BcykgdmFsdWVzIGluIHRoZSA8dT5UZXN0aW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRX0KY29sU3Vtcyhpcy5uYShkZi50ZXN0LnJhdykpCmBgYAo8ZGl2IHN0eWxlPSJjb2xvcjpibGFjaztiYWNrZ3JvdW5kLWNvbG9yOmxpZ2h0eWVsbG93Ij4KICAgPGJyPgogICA8Zm9udCBzaXplPSIrMC4zIj48c3BhbiBzdHlsZT0iY29sb3I6IGRhcmtibHVlIj5CYXNlZCBvbiB0aGUgZnJlcXVlbmN5IHRhYmxlLCB0aGVyZSBhcmUgYWxzbyA8c3Ryb25nPm5vPC9zdHJvbmc+IG1pc3NpbmcgdmFsdWVzIChOQXMpIGluIHRoZSA8c3Ryb25nPlRlc3Rpbmc8L3N0cm9uZz4gZGF0YSBmcmFtZS48L3NwYW4+PC9mb250PgogICA8YnI+CiAgIDxicj4KPC9kaXY+Cgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+RGlzcGxheWluZyB0aGUgY29udGVudCBvZiB0aGUgPHU+Zmlyc3QgdHdvIG9ic2VydmF0aW9uczwvdT4gb2YgdGhlIDxlbT5PcmlnaW5hbFR3ZWV0PC9lbT4gdmFyaWFibGUgd2l0aGluIHRoZSA8dT5UZXN0aW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRX0KZGYudGVzdC5yYXckT3JpZ2luYWxUd2VldFtbMV1dCmBgYApgYGB7ciBlY2hvID0gRkFMU0V9CmRmLnRlc3QucmF3JE9yaWdpbmFsVHdlZXRbWzJdXQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIHRoZSBmcmVxdWVuY3kgYW5kIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIDxlbT5TZW50aW1lbnQ8L2VtPiB2YXJpYWJsZSB3aXRoaW4gdGhlIDx1PlRlc3Rpbmc8L3U+IGRhdGEgc2V0Ojwvc3Ryb25nPjwvZm9udD4KYGBge3IgZWNobyA9IEZBTFNFfQp0YmwyLnJhdyA8LSB0YWJsZShkZi50ZXN0LnJhdyRTZW50aW1lbnQpCnRibDIucmF3IApgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBDYXRlZ29yeSBuYW1lcyAobGFiZWxzKToKbm1zMiA8LSBjKCJFLk4uIiwgIkUuUC4iLCAiTi4iLCAiTmUuIiwgIlAuIikKIyBDYXRlZ29yeSBjb2xvcnM6CmNscnMyIDwtIGMoImJyb3duIiwgImRhcmtncmVlbiIsICJjb3JhbCIsICJ3aGl0ZSIsICJsaWdodGdyZWVuIikKCiMgQ3JlYXRpb24gb2YgdGhlIGJhciBwbG90IHdpdGggY29sb3JzIGFuZCBjdXN0b21pemVkIGJhciB3aWR0aDoKYmFycGxvdCh0YmwyLnJhdywgbmFtZXMuYXJnID0gbm1zMiwgbWFpbiA9ICJTZW50aW1lbnQncyBkaXN0cmlidXRpb24gaW4gdGhlIFRlc3RpbmcgZGF0YSBzZXRcbihmcmVxdWVuY3kpIiwgY29sID0gY2xyczIsIHdpZHRoID0gYygxLjEsIDEuMiwgMS43LCAxLCAxLjUpLCB4bGFiID0gIkZyZXF1ZW5jeSIsIHlsYWIgPSAiQ2F0ZWdvcmllcyIsIGZvbnQubGFiID0gMywgY29sLmxhYiA9ICJibHVlIiwgaG9yaXogPSBUUlVFKQoKIyBGb3IgbGluZXMgYW5kIGFuZ2xlczoKIyBkZW5zaXR5ID0gYygxMDAsMTAwLDEwMCwwLDEwMCksIGFuZ2xlID0gYygwLDAsOTAsMTEsMCkKYGBgCjwhLS0gaHR0cHM6Ly9zZWFyY2guci1wcm9qZWN0Lm9yZy9DUkFOL3JlZm1hbnMvcGxvdHJpeC9odG1sL3BpZTNELmh0bWwgLS0+CmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBGb3IgdGhlIDNEIEV4cGxvZGVkIFBpZSBDaGFydCIKbGlicmFyeShwbG90cml4KQpgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBDYXRlZ29yeSBuYW1lcyAobGFiZWxzKToKbmFtZXMgPC0gYygiRXh0bS5OZWcuIiwgIkV4dG0uUG9zLiIsICJOZWcuIiwgIk5ldXQuIiwgIlBvcy4iKQojIENhdGVnb3J5IHBlcmNlbnRhZ2VzOgpwZXJjZW50YWdlIDwtIHJvdW5kKHRibDIucmF3IC8gbGVuZ3RoKGRmLnRlc3QucmF3JFNlbnRpbWVudCkgKiAxMDAsIDIpCiMgQWRkaW5nIHRoZSBmaXJzdCBwYXJlbnRoZXNpcyB0byB0aGUgbGFiZWxzOgpsYmxzIDwtIHBhc3RlKCIoIiwgbmFtZXMsIHNlcCA9ICIiKQojIEFkZGluZyB0aGUgc2Vjb25kIHBhcmVudGhlc2lzIGFuZCB0aGUgcGVyY2VudGFnZXMgdG8gbGFiZWxzOgpsYmxzIDwtIHBhc3RlKGxibHMsIHBlcmNlbnRhZ2UsIHNlcCA9ICIpICIpCiMgQWRkaW5nIHRoZSAlIHN5bWJvbHMgdG8gbGFiZWxzCmxibHMgPC0gcGFzdGUobGJscywiJSIsc2VwID0gIiIpCgojIENyZWF0aW5nIHRoZSBwaWUgY2hhcnQgd2l0aCB0aGUgbGFiZWxzIGFuZCBwZXJjZW50YWdlcywgYW5kIHdpdGggdGhlIHNhbWUgY29sb3JzIGFzIGluIHRoZSBiYXJwbG90LgpwaWUzRCh0YmwyLnJhdywgbGFiZWxzID0gbGJscywgZXhwbG9kZSA9IDAuMDUsIG1haW4gPSAiU2VudGltZW50J3MgZGlzdHJpYnV0aW9uIGluIHRoZSBUZXN0aW5nIGRhdGEgc2V0XG4ocGVyY2VudGFnZSkiLCBzdWIgPSAiUGllIENoYXJ0IG9mIGRpc3RyaWJ1dGlvbiIsIGNvbCA9IGNscnMyLCB0aGV0YSA9IDEuMiwgaGVpZ2h0ID0gMC4wMDUsIHN0YXJ0ID0gODYpCmBgYAoKPGJyPgo8Zm9udCBzaXplPSIrMiI+PHNwYW4gc3R5bGU9ImNvbG9yOiBuYXZ5OyI+PHN0cm9uZz5EYXRhIFByZXByb2Nlc3Npbmc8L3N0cm9uZz48L3NwYW4+PC9mb250Pgo8YnI+Cjxicj4KCmBgYHtyIGVjaG8gPSBGQUxTRX0KbGlicmFyeShzdHJpbmdyKQpgYGAKPGZvbnQgc2l6ZT0iKzEiIGNvbG9yPSJtYWdlbnRhIj48c3Ryb25nPlRyYWluaW5nIGRhdGEgc2V0PC9zdHJvbmc+PC9mb250Pgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+UmVwbGFjaW5nIHRoZSBlbnRyaWVzIGxhYmVsZWQgYXMgPHU+RXh0cmVtZWx5IFBvc2l0aXZlPC91PiB3aXRoIDx1PlBvc2l0aXZlPC91PiBhbmQgdGhlIGVudHJpZXMgbGFiZWxlZCBhcyA8dT5FeHRyZW1lbHkgTmVnYXRpdmU8L3U+IHdpdGggPHU+TmVnYXRpdmU8L3U+IG9mIHRoZSA8ZW0+U2VudGltZW50PC9lbT4gdmFyaWFibGUgaW4gdGhlIDx1PlRyYWluaW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyfQp0cmFpbmluZyRTZW50aW1lbnRbdHJhaW5pbmckU2VudGltZW50ID09ICJFeHRyZW1lbHkgUG9zaXRpdmUiXSA8LSAiUG9zaXRpdmUiCnRyYWluaW5nJFNlbnRpbWVudFt0cmFpbmluZyRTZW50aW1lbnQgPT0gIkV4dHJlbWVseSBOZWdhdGl2ZSJdIDwtICJOZWdhdGl2ZSIKYGBgCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIHRoZSBmcmVxdWVuY3kgYW5kIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIDxlbT5TZW50aW1lbnQ8L2VtPiB2YXJpYWJsZSB3aXRoaW4gdGhlIDx1PlRyYWluaW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRX0KdGFibGUodHJhaW5pbmckU2VudGltZW50KQpgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBDYXRlZ29yeSBuYW1lcyAobGFiZWxzKToKbm1zIDwtIGMoIk5lZy4iLCAiTmV1dC4iLCAiUG9zLiIpCiMgQ2F0ZWdvcnkgY29sb3JzOgpjbHJzIDwtIGMoInBpbmsiLCAid2hpdGUiLCAibGlnaHRibHVlMiIpCgojIENyZWF0aW9uIG9mIHRoZSBiYXIgcGxvdCB3aXRoIGNvbG9ycyBhbmQgY3VzdG9taXplZCBiYXIgd2lkdGg6CmJhcnBsb3QodGFibGUodHJhaW5pbmckU2VudGltZW50KSwgbmFtZXMuYXJnID0gbm1zLCBtYWluID0gIlNlbnRpbWVudCdzIGRpc3RyaWJ1dGlvbiBpbiB0aGUgVHJhaW5pbmcgZGF0YSBzZXRcbihmcmVxdWVuY3kpIiwgY29sID0gY2xycywgd2lkdGggPSBjKDEuNSwgMSwgMS43KSwgeGxhYiA9ICJDYXRlZ29yaWVzIiwgeWxhYiA9ICJGcmVxdWVuY3kiLCBmb250LmxhYiA9IDMsIGNvbC5sYWIgPSAiYmx1ZSIpCmBgYAoKYGBge3IgZWNobyA9IEZBTFNFfQojIENhdGVnb3J5IG5hbWVzIChsYWJlbHMpOgpubXMgPC0gYygiTmVnLiIsICJOZXV0LiIsICJQb3MuIikKIyBDYXRlZ29yeSBwZXJjZW50YWdlczoKcGVyY2VudGFnZSA8LSByb3VuZCh0YWJsZSh0cmFpbmluZyRTZW50aW1lbnQpIC8gbGVuZ3RoKHRyYWluaW5nJFNlbnRpbWVudCkgKiAxMDAsIDIpCiMgQWRkaW5nIHRoZSBmaXJzdCBwYXJlbnRoZXNpcyB0byB0aGUgbGFiZWxzOgpsYmxzIDwtIHBhc3RlKCIoIiwgbm1zLCBzZXAgPSAiIikKIyBBZGRpbmcgdGhlIHNlY29uZCBwYXJlbnRoZXNpcyBhbmQgdGhlIHBlcmNlbnRhZ2VzIHRvIGxhYmVsczoKbGJscyA8LSBwYXN0ZShsYmxzLCBwZXJjZW50YWdlLCBzZXAgPSAiKSAiKQojIEFkZGluZyB0aGUgJSBzeW1ib2xzIHRvIGxhYmVscwpsYmxzIDwtIHBhc3RlKGxibHMsIiUiLHNlcCA9ICIiKQoKIyBDcmVhdGluZyB0aGUgcGllIGNoYXJ0IHdpdGggdGhlIGxhYmVscyBhbmQgcGVyY2VudGFnZXMsIGFuZCB3aXRoIHRoZSBzYW1lIGNvbG9ycyBhcyBpbiB0aGUgYmFycGxvdC4KcGllKHRhYmxlKHRyYWluaW5nJFNlbnRpbWVudCksIG1haW4gPSAiU2VudGltZW50J3MgZGlzdHJpYnV0aW9uIGluIHRoZSBUcmFpbmluZyBkYXRhIHNldFxuKHBlcmNlbnRhZ2UpIiwgbGFiZWxzID0gbGJscywgY29sID0gYygicGluayIsICJ3aGl0ZSIsICJsaWdodGJsdWUyIikpCmBgYAo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPkZhY3Rvcml6aW5nIHRoZSA8ZW0+U2VudGltZW50PC9lbT4gdmFyaWFibGUsIGFzc2lnbmluZyBudW1lcmljIHZhbHVlcyB0byB0aGUgcmVzdWx0aW5nIGZhY3RvcnMsIGFuZCBhZGRpbmcgdGhlbSB0byB0aGUgPHU+VHJhaW5pbmc8L3U+IGRhdGEgc2V0IGFzIGEgbmV3IGNvbHVtbiBuYW1lZCA8ZW0+TGFiZWxzPC9lbT46PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gVFJVRX0KdHJhaW5pbmdbIkxhYmVscyJdIDwtIGFzLmludGVnZXIoYXMuZmFjdG9yKHRyYWluaW5nJFNlbnRpbWVudCkpIC0gMQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIHRoZSBmcmVxdWVuY3kgb2YgdGhlIDxlbT5MYWJlbHM8L2VtPiB2YXJpYWJsZSB3aXRoaW4gdGhlIDx1PlRyYWluaW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRX0KdGFibGUodHJhaW5pbmckTGFiZWxzKQpgYGAKCjxkaXYgc3R5bGU9ImNvbG9yOmJsYWNrO2JhY2tncm91bmQtY29sb3I6bGlnaHR5ZWxsb3ciPgogICA8YnI+CiAgIDxmb250IHNpemU9IiswLjMiPjxzcGFuIHN0eWxlPSJjb2xvcjogZGFya2JsdWUiPlRoZSBmcmVxdWVuY3kgY291bnRzIG9mIHRoZSA8c3Ryb25nPkxhYmVsczwvc3Ryb25nPiB2YXJpYWJsZSBleGFjdGx5IG1hdGNoIHRob3NlIG9mIHRoZSBmcmVxdWVuY3kgb2YgdGhlIDxzdHJvbmc+U2VudGltZW50PC9zdHJvbmc+IGNvbHVtbiBpbiB0aGUgPHU+VHJhaW5pbmc8L3U+IGRhdGEgc2V0Li48L3NwYW4+PC9mb250PgogICA8YnI+CiAgIDxicj4KPC9kaXY+CgpgYGB7ciBlY2hvID0gRkFMU0V9CmxpYnJhcnkodGV4dGNsZWFuKQpsaWJyYXJ5KFNub3diYWxsQykKbGlicmFyeShodW5zcGVsbCkKbGlicmFyeShOTFApCmxpYnJhcnkodG0pCmBgYAo8IS0tCllvdSB3aWxsIG5lZWQgdGhlIHBhY2thZ2VzICJ0ZXh0Y2xlYW4iLCAidG0iIChwbHVzICJOTFAiKSBhbmQgIlNub3diYWxsQyIgKHBsdXMgImh1bnNwZWxsIiBmb3IgImNoZWNrX3RleHQoKSIpLgoKRm9yIHRleHQgbWluaW5nLCBiZWZvcmUgIlZlY3RvclNvdXJjZSIsIApkbyB0aGVzZSBpbiB0aGUgb3JkZXIgdGhleSBhcmU6CgoxLiByZXBsYWNlX25vbl9hc2NpaSgpCQkgLSAoZnJvbSB0ZXh0Y2xlYW4pIFJlcGxhY2VzIG5vbi1BU0NJSSB3aXRoIGVxdWl2YWxlbnQgb3IgcmVtb3ZlCjIuIHRvbG93ZXIoKSAtIChSJ3MgYnVpbHQtaW4gZnVuY3Rpb24pIENvbnZlcnRzIHRleHQgdG8gbG93ZXJjYXNlLgozLiByZXBsYWNlX2RhdGUoKQkJIC0gKGZyb20gdGV4dGNsZWFuKSBSZXBsYWNlcyBkYXRlcwo0LiByZXBsYWNlX3RpbWUoKQkJIC0gKGZyb20gdGV4dGNsZWFuKSBSZXBsYWNlcyB0aW1lIHN0YW1wcwo1LiByZXBsYWNlX21vbmV5KCkJCSAtIChmcm9tIHRleHRjbGVhbikgUmVwbGFjZXMgbW9uZXkgaW4gdGhlIGZvcm0gb2YgJFxkKy4/XGR7MCwyfQo2LiByZXBsYWNlX251bWJlcigpCS0gKGZyb20gdGV4dGNsZWFuKSBSZXBsYWNlcyBjb21tb24gbnVtYmVycwo3LiByZXBsYWNlX2NvbnRyYWN0aW9uKHdvcmRzLCAsIGlnbm9yZS5jYXNlID0gVFJVRSkJLSAoZnJvbSB0ZXh0Y2xlYW4pIFJlcGxhY2UgY29udHJhY3Rpb25zIHdpdGggYm90aCB3b3Jkcwo4LiByZXBsYWNlX2dyYWRlKCkJCSAtIChmcm9tIHRleHRjbGVhbikgUmVwbGFjZXMgZ3JhZGVzIChlLmcuLCDigJxBK+KAnSkgd2l0aCB3b3JkIGVxdWl2YWxlbnQKOS4gcmVwbGFjZV9lbWFpbCgpCQkgLSAoZnJvbSB0ZXh0Y2xlYW4pIFJlcGxhY2VzIGVtYWlscwoxMC4gcmVwbGFjZV9oYXNoKCkJCSAtIChmcm9tIHRleHRjbGVhbikgUmVwbGFjZXMgVHdpdHRlciBzdHlsZSBoYXNoIHRhZ3MgKGUuZy4sICNyc3RhdHMpLiBIYXNodGFnIHdvcmRzIHdvbid0IHByb3ZpZGUgYW55IHVzZWZ1bCBtZWFuaW5nIHRvIHRleHQgaW4gc2VudGltZW50IGFuYWx5c2lzLgoxMS4gcmVwbGFjZV90YWcoKQkJIC0gKGZyb20gdGV4dGNsZWFuKSBSZXBsYWNlcyBUd2l0dGVyIHN0eWxlIGhhbmRsZSB0YWcgKGUuZy4sIEB0cmlua2VyKQoxMi4gcmVwbGFjZV9odG1sKCkJCSAtIChmcm9tIHRleHRjbGVhbikgUmVwbGFjZXMgSFRNTCB0YWdzIGFuZCBzeW1ib2xzCjEzLiByZXBsYWNlX3VybCgpCQkgLSAoZnJvbSB0ZXh0Y2xlYW4pIFJlcGxhY2VzIFVSTHMKMTQuIHJlcGxhY2VfaW50ZXJuZXRfc2xhbmcod29yZHMsIGlnbm9yZS5jYXNlID0gVFJVRSkJIC0gCShmcm9tIHRleHRjbGVhbikgUmVwbGFjZSBJbnRlcm5ldCBzbGFuZyB3aXRoIHdvcmQgZXF1aXZhbGVudHMKMTUuIHJlcGxhY2VfZW1vamkoKQkJIC0gKGZyb20gdGV4dGNsZWFuKSBSZXBsYWNlcyBlbW9qaXMgd2l0aCB3b3JkIGVxdWl2YWxlbnQgb3IgdW5pcXVlIGlkZW50aWZpZXIKMTYuIHJlcGxhY2VfZW1vdGljb24oKQkJIC0gKGZyb20gdGV4dGNsZWFuKSBSZXBsYWNlcyBlbW90aWNvbnMgd2l0aCB3b3JkIGVxdWl2YWxlbnQKCjE3LiByZW1vdmVXb3Jkcyh3b3Jkcywgc3RvcHdvcmRzKCJlbmdsaXNoIikpIC0gKGZyb20gdG0pIFJlbW92ZXMgdGhlIHN0b3B3b3Jkcy4KCgoKMTguIHJlcGxhY2Vfc3ltYm9sKCkJCSAtIChmcm9tIHRleHRjbGVhbikgUmVwbGFjZXMgY29tbW9uIHN5bWJvbHMKMTkuIG1nc3ViKHdvcmRzLCAic3ltYm9sLXRvLWJlLXJlcGxhY2VkIiwgInJlcGxhY2VtZW50LXN5bWJvbCIpCSAtIGZyb20gKHRleHRjbGVhbikgTXVsdGlwbGUgZ3N1Yi4gRm9yIHNvbWUgcmVhc29uIFIgaXMgbm90IHJlbW92aW5nIHRoZSBzaW5nbGUgcXVvdGVzICcgYXV0b21hdGljYWxseSwgc28gdGhlIHJlYXNvbiBvZiB1c2luZyB0aGlzIGFmdGVyIHJlcGxhY2Vfc3ltYm9sKCkuCjIwLiBzdHJpcCgpCSAtIChmcm9tIHRleHRjbGVhbikgUmVtb3ZlIGFsbCBub24gd29yZCBjaGFyYWN0ZXJzCjIxLiByZXBsYWNlX2tlcm4oKQkJIC0gKGZyb20gdGV4dGNsZWFuKSBSZXBsYWNlIHNwYWNlcyBmb3IgPjIgbGV0dGVyLCBhbGwgY2FwLCB3b3JkcyBjb250YWluaW5nIHNwYWNlcyBpbiBiZXR3ZWVuIGxldHRlcnMKMjIuIHdvcmRTdGVtKHdvcmRzLCBsYW5ndWFnZSA9ICJlbmdsaXNoIikgLSAoZnJvbSBTbm93YmFsbEMpIEV4dHJhY3RzIHRoZSBzdGVtcyBvZiBlYWNoIG9mIHRoZSBnaXZlbiB3b3JkcyBpbiB0aGUgdmVjdG9yLiBUeXBlIGdldFN0ZW1MYW5ndWFnZXMoKSB0byBnZXQgYSBsaXN0IG9mIGxhbmd1YWdlcyBzdXBwb3J0ZWQgYnkgd29yZFN0ZW0oKS4KMjMuIHJlcGxhY2Vfd2hpdGUoKQkJIC0gKGZyb20gdGV4dGNsZWFuKSBSZXBsYWNlIHJlZ2V4IHdoaXRlIHNwYWNlIGNoYXJhY3RlcnMKCjI0LiBSZW1vdmUgcm93cyB3aXRoIGVtcHR5IHZhbHVlcyBpbiB0aGUgdGV4dCBjb2x1bW4gKHNlZSBOb3RlIDIgYmVsb3cpLgoKTm90ZSAxOiBVc2UgdGhlIGNoZWNrX3RleHQoKSB0byBzZWUgaWYgYWZ0ZXIgY2xlYW5pbmcgdGhlIHRleHQgdGhlcmUgYXJlIHNvbWUgcG90ZW50aWFsIGlzc3VlcyAobm90IGFsbCBvZiB0aGVtIGFyZSBuZWNlc3NhcnkgdG8gY29ycmVjdCksIGJ1dCBkbyBpdCBwcml2YXRlbHkgKGRvIG5vdCBkaXNwbGF5IGl0IGluIHRoZSBodG1sIGFuZCBjb21tZW50IGl0IHdoZW4gbm90IHVzaW5nIGl0LikKCiAgICAyNS4gY2hlY2tfdGV4dCgpCSAtIChmcm9tIHRleHRjbGVhbikgVGV4dCByZXBvcnQgb2YgcG90ZW50aWFsIGlzc3VlcwoKCk5vdGUgMjogSWYgeW91IGhhdmUgYSBtZXNzYWdlIGFib3V0IGFuIGVtcHR5IHJvdywgQ0hFQ0sgRklSU1QgdGhhdCB0aGUgcm93IGlzIGFjdHVhbGx5IGVtcHR5LCBub3QganVzdCBoYXZpbmcgc29tZSBvZiB0aGUgY2VsbHMgZW1wdHkuIERvIG5vdCB1c2UgdGhlIGRyb3BfZW1wdHlfcm93KCkgZnJvbSB0ZXh0Y2xlYW4sIGluc3RlYWQgZGVsZXRlIHRoZSByb3cgYXMgeW91IG5vcm1hbGx5IHdvdWxkIGRvLgoKICAgIHRyYWluaW5nIDwtIHRyYWluaW5nWyEodHJhaW5pbmckT3JpZ2luYWxUd2VldD09ICIiKSwgXQoKCmh0dHBzOi8vZ2l0aHViLmNvbS90cmlua2VyL3RleHRjbGVhbgotLT4KCgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+Q2xlYW5pbmcgYW5kIHRyYW5zZm9ybWluZyB0aGUgPHU+dGV4dDwvdT4gb2YgdGhlIDxlbT5PcmlnaW5hbFR3ZWV0PC9lbT4gdmFyaWFibGUgaW4gdGhlIDx1PlRyYWluaW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIHdhcm5pbmcgPSBGQUxTRX0KdHJhaW5pbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX25vbl9hc2NpaSh0cmFpbmluZyRPcmlnaW5hbFR3ZWV0KQp0cmFpbmluZyRPcmlnaW5hbFR3ZWV0IDwtIHRvbG93ZXIodHJhaW5pbmckT3JpZ2luYWxUd2VldCkKdHJhaW5pbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX2RhdGUodHJhaW5pbmckT3JpZ2luYWxUd2VldCkKdHJhaW5pbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX3RpbWUodHJhaW5pbmckT3JpZ2luYWxUd2VldCkKdHJhaW5pbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX21vbmV5KHRyYWluaW5nJE9yaWdpbmFsVHdlZXQpCnRyYWluaW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV9udW1iZXIodHJhaW5pbmckT3JpZ2luYWxUd2VldCkKdHJhaW5pbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX2NvbnRyYWN0aW9uKHRyYWluaW5nJE9yaWdpbmFsVHdlZXQsIGlnbm9yZS5jYXNlID0gVFJVRSkKCnRyYWluaW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV9ncmFkZSh0cmFpbmluZyRPcmlnaW5hbFR3ZWV0KQp0cmFpbmluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2VfZW1haWwodHJhaW5pbmckT3JpZ2luYWxUd2VldCkKdHJhaW5pbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX2hhc2godHJhaW5pbmckT3JpZ2luYWxUd2VldCkKdHJhaW5pbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX3RhZyh0cmFpbmluZyRPcmlnaW5hbFR3ZWV0KQp0cmFpbmluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2VfaHRtbCh0cmFpbmluZyRPcmlnaW5hbFR3ZWV0KQp0cmFpbmluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2VfdXJsKHRyYWluaW5nJE9yaWdpbmFsVHdlZXQpCnRyYWluaW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV9pbnRlcm5ldF9zbGFuZyh0cmFpbmluZyRPcmlnaW5hbFR3ZWV0LCBpZ25vcmUuY2FzZSA9IFRSVUUpCnRyYWluaW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV9lbW9qaSh0cmFpbmluZyRPcmlnaW5hbFR3ZWV0KQp0cmFpbmluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2VfZW1vdGljb24odHJhaW5pbmckT3JpZ2luYWxUd2VldCkKCnRyYWluaW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVtb3ZlV29yZHModHJhaW5pbmckT3JpZ2luYWxUd2VldCwgc3RvcHdvcmRzKCJlbmdsaXNoIikpCgp0cmFpbmluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2Vfc3ltYm9sKHRyYWluaW5nJE9yaWdpbmFsVHdlZXQpCgp0cmFpbmluZyRPcmlnaW5hbFR3ZWV0IDwtIG1nc3ViKHRyYWluaW5nJE9yaWdpbmFsVHdlZXQsICInIiwgIiIpCgp0cmFpbmluZyRPcmlnaW5hbFR3ZWV0IDwtIHN0cmlwKHRyYWluaW5nJE9yaWdpbmFsVHdlZXQpCnRyYWluaW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV9rZXJuKHRyYWluaW5nJE9yaWdpbmFsVHdlZXQpCnRyYWluaW5nJE9yaWdpbmFsVHdlZXQgPC0gd29yZFN0ZW0odHJhaW5pbmckT3JpZ2luYWxUd2VldCwgbGFuZ3VhZ2UgPSAiZW5nbGlzaCIpCnRyYWluaW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV93aGl0ZSh0cmFpbmluZyRPcmlnaW5hbFR3ZWV0KQoKdHJhaW5pbmcgPC0gdHJhaW5pbmdbISh0cmFpbmluZyRPcmlnaW5hbFR3ZWV0PT0gIiIpLCBdCmBgYAoKPCEtLSBPTkxZIHBlcmZvcm0gdGhpcyB0byBjaGVjayBpZiB0aGVyZSBhcmUgdGhpbmdzIHRoYXQgbmVlZCB0byBiZSBmaXhlZCBvciBpbXByb3ZlZCBhbmQKZG9uJ3QgZGlzcGxheSB0aGlzIGluIHRoZSBodG1sLiAtLT4KYGBge3IgZWNobyA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CiNjaGVja190ZXh0KHRyYWluaW5nJE9yaWdpbmFsVHdlZXQpCmBgYAoKPCEtLSBBICJ2b2xhdGlsZSBjb3Jwb3JhIiBpbiB0aGUgY29udGV4dCBvZiBSIHJlZmVycyB0byBhIGNvbGxlY3Rpb24gb2YgdGV4dCBkYXRhIHN0b3JlZCBhcyBSIG9iamVjdHMsIHRoYXQgaXMgY29tcGxldGVseSBzdG9yZWQgaW4gdGhlIGNvbXB1dGVyJ3MgbWVtb3J5IChSQU0pLiBUaGlzIG1lYW5zIHRoYXQgYWxsIHRoZSB0ZXh0IGluZm9ybWF0aW9uIGlzIHJlYWRpbHkgYXZhaWxhYmxlIGZvciBhbmFseXNpcywgYW5kIGFueSBjaGFuZ2VzIG9yIG9wZXJhdGlvbnMgYXJlIGRvbmUgZGlyZWN0bHkgaW4gdGhlIGNvbXB1dGVyJ3MgbWVtb3J5IHdpdGhvdXQgbmVjZXNzYXJpbHkgc2F2aW5nIHRoZW0gdG8gYSBtb3JlIHBlcm1hbmVudCBzdG9yYWdlIGxvY2F0aW9uIGxpa2UgYSBmaWxlLiAtLT4KCjwhLS0gIkNvcnBvcmEiIGFyZSBSIG9iamVjdHMgaGVsZCBmdWxseSBpbiBtZW1vcnkuIC0tPgoKPCEtLSAiQ29ycHVzIiB0eXBpY2FsbHkgcmVmZXJzIHRvIGEgY29sbGVjdGlvbiBvZiB0ZXh0IGRvY3VtZW50cy4gLS0+Cgo8IS0tICJWb2xhdGlsZSIgaW1wbGllcyB0aGF0IHRoZSBjb3JwdXMgaXMgZnVsbHkga2VwdCBpbiBtZW1vcnksIG1lYW5pbmcgdGhhdCBhbGwgdGhlIGRhdGEgYW5kIGNoYW5nZXMgdG8gdGhlIGNvcnB1cyBhcmUgc3RvcmVkIGluIHRoZSBjb21wdXRlcidzIFJBTSAoUmFuZG9tIEFjY2VzcyBNZW1vcnkpLiAtLT4KCgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+U2V0dGluZyB1cCBhIDx1PlZlY3RvciBTb3VyY2U8L3U+IHRvIHRyZWF0IGVhY2ggZWxlbWVudCBvZiB0aGUgPGVtPk9yaWdpbmFsVHdlZXQ8L2VtPiB2YXJpYWJsZSBpbiB0aGUgPHU+VHJhaW5pbmc8L3U+IGRhdGEgc2V0IGFzIGluZGl2aWR1YWwgZG9jdW1lbnRzOjwvc3Ryb25nPjwvZm9udD4KYGBge3J9CnRyYWluaW5nLnZzIDwtIFZlY3RvclNvdXJjZSh0cmFpbmluZyRPcmlnaW5hbFR3ZWV0KQpgYGAKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPkRpc3BsYXlpbmcgdGhlIHN0cnVjdHVyZSBvZiB0aGUgPHU+VHJhaW5pbmc8L3U+IHZlY3RvciBzb3VyY2U6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CnN0cih0cmFpbmluZy52cykKYGBgCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5DcmVhdGluZyBhIDx1PlZvbGF0aWxlIENvcnB1czwvdT4gZnJvbSB0aGUgPHU+VHJhaW5pbmc8L3U+IHZlY3RvciBzb3VyY2U6PC9zdHJvbmc+PC9mb250PgpgYGB7cn0KdHJhaW5pbmcudmMgPC0gVkNvcnB1cyh0cmFpbmluZy52cykKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgRGVsZXRpbmcgdW51c2VkIGRhdGEgZnJhbWU6CnJtKHRyYWluaW5nLnZzKQpgYGAKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPkRpc3BsYXlpbmcgZGV0YWlscyBhYm91dCB0aGUgPHU+Vm9sYXRpbGUgQ29ycHVzPC91Pjo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRX0KcHJpbnQodHJhaW5pbmcudmMpCmBgYAo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+RGlzcGxheWluZyBkZXRhaWxzIG9mIHRoZSA8dT5maXJzdCB0d28gZG9jdW1lbnRzPC91PiB3aXRoaW4gdGhlIDx1PlRyYWluaW5nPC91PiBWb2xhdGlsZSBDb3JwdXM6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CmNvbnRlbnQodHJhaW5pbmcudmNbMToyXSkKYGBgCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIHRoZSBjb250ZW50IG9mIHRoZSA8dT5maXJzdCB0d28gZG9jdW1lbnRzPC91PiB3aXRoaW4gdGhlIDx1PlRyYWluaW5nPC91PiBWb2xhdGlsZSBDb3JwdXM6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CmNvbnRlbnQodHJhaW5pbmcudmNbWzFdXSkKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CmNvbnRlbnQodHJhaW5pbmcudmNbWzJdXSkKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgQ3JlYXRpbmcgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBvZiB0aGUgVm9sYXRpbGUgQ29ycHVzLCBpbiBvcmRlciB0byBjcmVhdGUgdGhlIFdvcmRjbG91ZHM6CnRlbXAuZGYgPC0gZGF0YS5mcmFtZShUZXh0ID0gc2FwcGx5KHRyYWluaW5nLnZjLCBhcy5jaGFyYWN0ZXIpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCmBgYAoKYGBge3IgZWNobyA9IEZBTFNFfQojIEFkZGluZyB0aGUgU2VudGltZW50IGNvbHVtbiAobGFiZWxzKSB0byB0aGUgdGVtcG9yYXJ5IGRhdGEgZnJhbWU6CnRlbXAuZGZbIlNlbnRpbWVudCJdIDwtIHRyYWluaW5nJFNlbnRpbWVudApgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0KbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkod29yZGNsb3VkKQpgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBUbyBiZSB1c2VkIHRvIGRpc3BsYXkgd29yZGNsb3VkcyBvZiBvbmx5IHBvc2l0aXZlLCBuZWdhdGl2ZSwgb3IgbmV1dHJhbCBzZW50aW1lbnRzLgojIE5vdCBhbGwgd2lsbCBiZSB1c2VkIGluIHRoaXMgYW5hbHlzaXMuCnBvc2l0aXZlIDwtIHRlbXAuZGZbdGVtcC5kZiRTZW50aW1lbnQgPT0gIlBvc2l0aXZlIiwgXQpuZWdhdGl2ZSA8LSB0ZW1wLmRmW3RlbXAuZGYkU2VudGltZW50ID09ICJOZWdhdGl2ZSIsIF0KbmV1dHJhbCA8LSB0ZW1wLmRmW3RlbXAuZGYkU2VudGltZW50ID09ICJOZXV0cmFsIiwgXQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIGEgPHU+V29yZGNsb3VkPC91PiBvZiB0aGUgPHU+dG9wIDEwMCBtb3N0IGZyZXF1ZW50IHdvcmRzPC91Pjo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQojIG1heC53b3JkcyBsaW1pdHMgdGhlIHdvcmQgY2xvdWQgdG8gZGlzcGxheSB0aGUgdG9wIDEwMCBtb3N0IGZyZXF1ZW50IHdvcmRzIGZyb20gdGhlIHRleHQgZGF0YS4KIyBJbiBzY2FsZSwgdGhlIGZpcnN0IHZhbHVlICgzKSBkZXRlcm1pbmVzIHRoZSBtYXhpbXVtIHNpemUgb2YgdGhlIHdvcmRzLCB3aGlsZSB0aGUgc2Vjb25kIHZhbHVlICgwLjUpIGRldGVybWluZXMgdGhlIG1pbmltdW0gc2l6ZS4gTGFyZ2VyIHdvcmRzIHdpbGwgYmUgc2NhbGVkIHVwIHRvIHRocmVlICgzKSB0aW1lcyB0aGVpciBub3JtYWwgc2l6ZSwgYW5kIHNtYWxsZXIgd29yZHMgd2lsbCBiZSBzY2FsZWQgZG93biB0byBoYWxmICgwLjUpIHRoZWlyIG5vcm1hbCBzaXplLgp3b3JkY2xvdWQodGVtcC5kZiRUZXh0LCBtYXgud29yZHMgPSAxMDAsIHNjYWxlID0gYygzLCAwLjUpKQpgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0KbGlicmFyeShzdHJpbmdyKQpgYGAKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPkRpc3BsYXlpbmcgYSBsaXN0IG9mIHRoZSA8dT50b3AgMTAgbW9zdCBmcmVxdWVudCB3b3JkczwvdT46PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgRXh0cmFjdCB3b3JkcyBmcm9tIHRlbXAuZGYkVGV4dDoKd29yZHMgPC0gdW5saXN0KHN0cl9leHRyYWN0X2FsbCh0ZW1wLmRmJFRleHQsICJcXGJcXHcrXFxiIikpCiMgQ3JlYXRlcyBhIGZyZXF1ZW5jeSB0YWJsZSBvZiAid29yZHMiOgpmcmVxLm9mLndvcmRzIDwtIHRhYmxlKHdvcmRzKQojIFNvcnQgdGhlICJmcmVxdWVuY3kub2Yud29yZHMiIHRhYmxlOgpmcmVxLnNvcnRlZCA8LSBzb3J0KGZyZXEub2Yud29yZHMsIGRlY3JlYXNpbmcgPSBUUlVFKQojIFJldHJpZXZlcyB0aGUgMTAgdG9wIHdvcmRzIGZyb20gdGhlICJmcmVxLnNvcnRlZCIgdGFibGUgYW5kIGRpc3BsYXkgaXQgYXMgYSBkYXRhIGZyYW1lOgphcy5kYXRhLmZyYW1lKHRvcC50ZW4gPC0gaGVhZChmcmVxLnNvcnRlZCwgMTApKQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIGEgPHU+V29yZGNsb3VkPC91PiBvZiB0aGUgPHU+dG9wIDEwMCBtb3N0IGZyZXF1ZW50IHdvcmRzPC91PiBvZiB0aGUgPHU+cG9zaXRpdmUgc2VudGltZW50czwvdT46PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KIyBtYXgud29yZHMgbGltaXRzIHRoZSB3b3JkIGNsb3VkIHRvIGRpc3BsYXkgdGhlIHRvcCAxMDAgbW9zdCBmcmVxdWVudCB3b3JkcyBmcm9tIHRoZSB0ZXh0IGRhdGEuCiMgSW4gc2NhbGUsIHRoZSBmaXJzdCB2YWx1ZSAoMykgZGV0ZXJtaW5lcyB0aGUgbWF4aW11bSBzaXplIG9mIHRoZSB3b3Jkcywgd2hpbGUgdGhlIHNlY29uZCB2YWx1ZSAoMC41KSBkZXRlcm1pbmVzIHRoZSBtaW5pbXVtIHNpemUuIExhcmdlciB3b3JkcyB3aWxsIGJlIHNjYWxlZCB1cCB0byB0aHJlZSAoMykgdGltZXMgdGhlaXIgbm9ybWFsIHNpemUsIGFuZCBzbWFsbGVyIHdvcmRzIHdpbGwgYmUgc2NhbGVkIGRvd24gdG8gaGFsZiAoMC41KSB0aGVpciBub3JtYWwgc2l6ZS4Kd29yZGNsb3VkKHBvc2l0aXZlJFRleHQsIG1heC53b3JkcyA9IDEwMCwgc2NhbGUgPSBjKDMsIDAuNSkpCmBgYAo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+RGlzcGxheWluZyBhIGxpc3Qgb2YgdGhlIDx1PnRvcCAxMCBtb3N0IGZyZXF1ZW50IHdvcmRzPC91PiBvZiB0aGUgPHU+cG9zaXRpdmUgc2VudGltZW50czwvdT46PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgRXh0cmFjdCB3b3JkcyBmcm9tIHBvc2l0aXZlJFRleHQ6CndvcmRzIDwtIHVubGlzdChzdHJfZXh0cmFjdF9hbGwocG9zaXRpdmUkVGV4dCwgIlxcYlxcdytcXGIiKSkKIyBDcmVhdGVzIGEgZnJlcXVlbmN5IHRhYmxlIG9mICJ3b3JkcyI6CmZyZXEub2Yud29yZHMgPC0gdGFibGUod29yZHMpCiMgU29ydCB0aGUgImZyZXF1ZW5jeS5vZi53b3JkcyIgdGFibGU6CmZyZXEuc29ydGVkIDwtIHNvcnQoZnJlcS5vZi53b3JkcywgZGVjcmVhc2luZyA9IFRSVUUpCiMgUmV0cmlldmVzIHRoZSAxMCB0b3Agd29yZHMgZnJvbSB0aGUgImZyZXEuc29ydGVkIiB0YWJsZSBhbmQgZGlzcGxheSBpdCBhcyBhIGRhdGEgZnJhbWU6CmFzLmRhdGEuZnJhbWUodG9wLnRlbiA8LSBoZWFkKGZyZXEuc29ydGVkLCAxMCkpCmBgYAoKPCEtLSBBIGRvY3VtZW50LXRlcm0gbWF0cml4IGlzIGEgbWF0aGVtYXRpY2FsIG1hdHJpeCB0aGF0IGRlc2NyaWJlcyB0aGUgZnJlcXVlbmN5IG9mIHRlcm1zIHRoYXQgb2NjdXIgaW4gYSBlYWNoIGRvY3VtZW50IGluIGEgY29sbGVjdGlvbi4gSW4gYSBkb2N1bWVudC10ZXJtIG1hdHJpeCwgcm93cyBjb3JyZXNwb25kIHRvIGRvY3VtZW50cyBpbiB0aGUgY29sbGVjdGlvbiBhbmQgY29sdW1ucyBjb3JyZXNwb25kIHRvIHRlcm1zLiAgLS0+Cjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5HZW5lcmF0aW5nIGEgPHU+RG9jdW1lbnQtVGVybSBNYXRyaXg8L3U+IGZyb20gdGhlIDx1PlRyYWluaW5nPC91PiBWb2xhdGlsZSBDb3JwdXMgdG8gZGVwaWN0IHRoZSBmcmVxdWVuY3kgb2YgdGVybXMgd2l0aGluIGVhY2ggZG9jdW1lbnQgaW4gdGhlIGNvbGxlY3Rpb246PC9zdHJvbmc+PC9mb250PgpgYGB7cn0KZHRtIDwtIERvY3VtZW50VGVybU1hdHJpeCh0cmFpbmluZy52YykKYGBgCgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+SW5zcGVjdGluZyB0aGUgY29udGVudHMgb2YgdGhlIERvY3VtZW50LVRlcm0gTWF0cml4IGFuZCBkaXNwbGF5aW5nIGl0IGluIGEgaHVtYW4tcmVhZGFibGUgZm9ybWF0LiBUaGlzIGRpc3BsYXlzIHRlcm1zIGFuZCB0aGVpciBmcmVxdWVuY2llcyB3aXRoaW4gZWFjaCBkb2N1bWVudCBpbiB0aGUgY29sbGVjdGlvbjo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyfQp0bTo6aW5zcGVjdChkdG0pCmBgYAoKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPlNob3dpbmcgdGhlIG51bWJlciBvZiB0ZXJtcyB0aGF0IGFyZSByZXBlYXRlZCA8dT4xMDAgdGltZXMgb3IgbW9yZTwvdT4gaW4gdGhlIERvY3VtZW50LVRlcm0gTWF0cml4IGZyb20gdGhlIDx1PlRyYWluaW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyfQojIEdldHMgYSBsaXN0IG9mIHRob3NlIHRlcm1zIHJlcGVhdGVkIDEwMCB0aW1lcyBvciBtb3JlIGZyb20gdGhlIERvY3VtZW50LVRlcm0gTWF0cml4OgpoaWdoLmZyZXEudGVybXMgPC0gZmluZEZyZXFUZXJtcyhkdG0sIGxvd2ZyZXEgPSAxMDApCiMgRGlzcGxheSB0aGUgcXVhbnRpdHkgb2YgdGhvc2UgdGVybXMgcmVwZWF0ZWQgMTAwIHRpbWVzIG9yIG1vcmU6Cmxlbmd0aChoaWdoLmZyZXEudGVybXMpCmBgYAoKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPkRpc3BsYXlpbmcgYSBsaXN0IG9mIHRlcm1zIHJlcGVhdGVkIDx1PjEwMCB0aW1lcyBvciBtb3JlPC91PiBpbiB0aGUgRG9jdW1lbnQtVGVybSBNYXRyaXggZnJvbSB0aGUgPHU+VHJhaW5pbmc8L3U+IGRhdGEgc2V0Ojwvc3Ryb25nPjwvZm9udD4KYGBge3IgZWNobyA9IEZBTFNFfQojIEdldHMgdGhlIG5hbWVzIGFuZCB0aGUgZnJlcXVlbmN5IG9mIHRob3NlIHRlcm1zIHJlcGVhdGVkIDEwMCB0aW1lcyBvciBtb3JlIGZyb20gdGhlIAojIERvY3VtZW50LVRlcm0gTWF0cml4IGFuZCBzdG9yZSB0aGVtIGFzIGEgTWF0cml4OgpoaWdoLnRlcm0uZnJlcXVlbmNpZXMgPC0gY29sU3Vtcyhhcy5tYXRyaXgoZHRtWywgaGlnaC5mcmVxLnRlcm1zXSkpCiMgU29ydHMgdGhlICJoaWdoLnRlcm0uZnJlcXVlbmNpZXMiIG1hdHJpeDoKc29ydGVkLmhpZ2gudGVybS5mcmVxdWVuY2llcyA8LSBzb3J0KGhpZ2gudGVybS5mcmVxdWVuY2llcywgZGVjcmVhc2luZyA9IFRSVUUpCiMgRGlzcGxheXMgdGhlICJzb3J0ZWQuaGlnaC50ZXJtLmZyZXF1ZW5jaWVzIiBtYXRyaXggYXMgYSBkYXRhIGZyYW1lIChpbiBvcmRlciB0byBpbXByb3ZlCiMgcmVhZGFiaWxpdHkgYnkgc2hvd2luZyB0aGUgcmVzdWx0cyBhcyBhIHRhYmxlIHdpdGggbXVsdGlwbGUgdGFicyk6CnNvcnRlZC5oaWdoLnRlcm0uZnJlcXVlbmNpZXMuZGYgPC0gYXMuZGF0YS5mcmFtZShzb3J0ZWQuaGlnaC50ZXJtLmZyZXF1ZW5jaWVzKQpzb3J0ZWQuaGlnaC50ZXJtLmZyZXF1ZW5jaWVzLmRmCmBgYAoKYGBge3IgZWNobyA9IEZBTFNFfQojIERlbGV0aW5nIHZhcmlhYmxlcyB0aGF0IHdpbGwgbm90IGJlIHVzZWQgbGF0ZXI6CnJtKGhpZ2gudGVybS5mcmVxdWVuY2llcykKcm0oc29ydGVkLmhpZ2gudGVybS5mcmVxdWVuY2llcykKcm0oc29ydGVkLmhpZ2gudGVybS5mcmVxdWVuY2llcy5kZikKYGBgCgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+U2hvd2luZyB0aGUgbnVtYmVyIG9mIHRlcm1zIHRoYXQgYXJlIHJlcGVhdGVkIDx1Pmxlc3MgdGhhbiAxMDAgdGltZXM8L3U+IGluIHRoZSBEb2N1bWVudC1UZXJtIE1hdHJpeCBmcm9tIHRoZSA8dT5UcmFpbmluZzwvdT4gZGF0YSBzZXQ6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgR2V0cyBhIGxpc3Qgb2YgdGhvc2UgdGVybXMgcmVwZWF0ZWQgbGVzcyB0aGFuIDEwMCB0aW1lcyBmcm9tIHRoZSBEb2N1bWVudC1UZXJtIE1hdHJpeDoKbG93LmZyZXEudGVybXMgPC0gZmluZEZyZXFUZXJtcyhkdG0sIGhpZ2hmcmVxID0gOTkpCiMgRGlzcGxheSB0aGUgcXVhbnRpdHkgb2YgdGhvc2UgdGVybXMgcmVwZWF0ZWQgbGVzcyB0aGFuIDEwMCB0aW1lczoKbGVuZ3RoKGxvdy5mcmVxLnRlcm1zKQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIGEgbGlzdCBvZiB0ZXJtcyByZXBlYXRlZCA8dT5sZXNzIDEwMCB0aW1lczwvdT4gKHdpdGggYSBsb3cgZnJlcXVlbmN5IG9mIDkwKSBpbiB0aGUgRG9jdW1lbnQtVGVybSBNYXRyaXggZnJvbSB0aGUgPHU+VHJhaW5pbmc8L3U+IGRhdGEgc2V0Ojwvc3Ryb25nPjwvZm9udD4KYGBge3IgZWNobyA9IEZBTFNFfQojIEdldHMgdGhlIG5hbWVzIGFuZCB0aGUgZnJlcXVlbmN5IG9mIHNvbWUgb2YgdGhvc2UgdGVybXMgcmVwZWF0ZWQgbGVzcyB0aGFuIDEwMCAoOTAtOTkpIHRpbWVzIAojIGZyb20gdGhlIERvY3VtZW50LVRlcm0gTWF0cml4IGFuZCBzdG9yZSB0aGVtIGFzIGEgTWF0cml4Ogpsb3cudGVybS5mcmVxdWVuY2llcyA8LSBjb2xTdW1zKGFzLm1hdHJpeChkdG1bLCBmaW5kRnJlcVRlcm1zKGR0bSwgaGlnaGZyZXEgPSA5OSwgbG93ZnJlcSA9IDkwKSBdKSkKIyBTb3J0cyB0aGUgImxvdy50ZXJtLmZyZXF1ZW5jaWVzIiBtYXRyaXg6CnNvcnRlZC5sb3cudGVybS5mcmVxdWVuY2llcyA8LSBzb3J0KGxvdy50ZXJtLmZyZXF1ZW5jaWVzLCBkZWNyZWFzaW5nID0gVFJVRSkKIyBEaXNwbGF5cyB0aGUgInNvcnRlZC5sb3cudGVybS5mcmVxdWVuY2llcyIgbWF0cml4IGFzIGEgZGF0YSBmcmFtZSAoaW4gb3JkZXIgdG8gaW1wcm92ZQojIHJlYWRhYmlsaXR5IGJ5IHNob3dpbmcgdGhlIHJlc3VsdHMgYXMgYSB0YWJsZSB3aXRoIG11bHRpcGxlIHRhYnMpOgpzb3J0ZWQubG93LnRlcm0uZnJlcXVlbmNpZXMuZGYgPC0gYXMuZGF0YS5mcmFtZShzb3J0ZWQubG93LnRlcm0uZnJlcXVlbmNpZXMpCnNvcnRlZC5sb3cudGVybS5mcmVxdWVuY2llcy5kZgpgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBEZWxldGluZyB2YXJpYWJsZXMgdGhhdCB3aWxsIG5vdCBiZSB1c2VkIGxhdGVyOgpybShsb3cuZnJlcS50ZXJtcykKcm0obG93LnRlcm0uZnJlcXVlbmNpZXMpCnJtKHNvcnRlZC5sb3cudGVybS5mcmVxdWVuY2llcykKcm0oc29ydGVkLmxvdy50ZXJtLmZyZXF1ZW5jaWVzLmRmKQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5SZW1vdmluZyB0aG9zZSB0ZXJtcyByZXBlYXRlZCBsZXNzIHRoYW4gMTAwIHRpbWVzIGZyb20gdGhlIERvY3VtZW50LVRlcm0gTWF0cml4IGZyb20gdGhlIDx1PlRyYWluaW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyfQpkdG0gPC0gZHRtWywgY29sbmFtZXMoZHRtKSAlaW4lIGhpZ2guZnJlcS50ZXJtc10KYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgRGVsZXRpbmcgdmFyaWFibGVzIHRoYXQgd2lsbCBub3QgYmUgdXNlZCBsYXRlcjoKcm0oaGlnaC5mcmVxLnRlcm1zKQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5Db25maXJtaW5nIHRoZXJlIGFyZSBubyB0ZXJtcyByZXBlYXRlZCA8dT5sZXNzIHRoYW4gMTAwIHRpbWVzPC91PiBpbiB0aGUgRG9jdW1lbnQtVGVybSBNYXRyaXggZnJvbSB0aGUgPHU+VHJhaW5pbmc8L3U+IGRhdGEgc2V0Ojwvc3Ryb25nPjwvZm9udD4KYGBge3J9CmNhdCgiVGVybXMgcmVwZWF0ZWQgbGVzcyB0aGFuIDEwMCB0aW1lczogIiwgbGVuZ3RoKGZpbmRGcmVxVGVybXMoZHRtLCBoaWdoZnJlcSA9IDk5KSkpCmBgYAoKYGBge3IgZWNobyA9IEZBTFNFfQojc3RyKHRkbSkKI2luc3BlY3QodGRtWzE6MyxdKQojdGRtW1sxXV0KI3RtOjppbnNwZWN0KHRkbSkKI3RtOjppbnNwZWN0KHRkbVsxOjUsIF0pCmBgYAoKPGJyPgo8YnI+Cjxmb250IHNpemU9IisxIiBjb2xvcj0ibWFnZW50YSI+PHN0cm9uZz5UZXN0aW5nIGRhdGEgc2V0PC9zdHJvbmc+PC9mb250Pgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+UmVwbGFjaW5nIHRoZSBlbnRyaWVzIGxhYmVsZWQgYXMgPHU+RXh0cmVtZWx5IFBvc2l0aXZlPC91PiB3aXRoIDx1PlBvc2l0aXZlPC91PiBhbmQgdGhlIGVudHJpZXMgbGFiZWxlZCBhcyA8dT5FeHRyZW1lbHkgTmVnYXRpdmU8L3U+IHdpdGggPHU+TmVnYXRpdmU8L3U+IG9mIHRoZSA8ZW0+U2VudGltZW50PC9lbT4gdmFyaWFibGUgaW4gdGhlIDx1PlRlc3Rpbmc8L3U+IGRhdGEgc2V0Ojwvc3Ryb25nPjwvZm9udD4KYGBge3J9CnRlc3RpbmckU2VudGltZW50W3Rlc3RpbmckU2VudGltZW50ID09ICJFeHRyZW1lbHkgUG9zaXRpdmUiXSA8LSAiUG9zaXRpdmUiCnRlc3RpbmckU2VudGltZW50W3Rlc3RpbmckU2VudGltZW50ID09ICJFeHRyZW1lbHkgTmVnYXRpdmUiXSA8LSAiTmVnYXRpdmUiCmBgYAoKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPkRpc3BsYXlpbmcgdGhlIGZyZXF1ZW5jeSBhbmQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgPGVtPlNlbnRpbWVudDwvZW0+IHZhcmlhYmxlIHdpdGhpbiB0aGUgPHU+VGVzdGluZzwvdT4gZGF0YSBzZXQ6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CnRhYmxlKHRlc3RpbmckU2VudGltZW50KQpgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBDYXRlZ29yeSBuYW1lcyAobGFiZWxzKToKbm1zMiA8LSBjKCJOZWcuIiwgIk5ldXQuIiwgIlBvcy4iKQojIENhdGVnb3J5IGNvbG9yczoKY2xyczIgPC0gYygiY29yYWwiLCAid2hpdGUiLCAibGlnaHRncmVlbiIpCgojIENyZWF0aW9uIG9mIHRoZSBiYXIgcGxvdCB3aXRoIGNvbG9ycyBhbmQgY3VzdG9taXplZCBiYXIgd2lkdGg6CmJhcnBsb3QodGFibGUodGVzdGluZyRTZW50aW1lbnQpLCBuYW1lcy5hcmcgPSBubXMyLCBtYWluID0gIlNlbnRpbWVudCdzIGRpc3RyaWJ1dGlvbiBpbiB0aGUgVGVzdGluZyBkYXRhIHNldFxuKGZyZXF1ZW5jeSkiLCBjb2wgPSBjbHJzMiwgd2lkdGggPSBjKDEuNywgMC44LCAxLjUpLCB4bGFiID0gIkZyZXF1ZW5jeSIsIHlsYWIgPSAiQ2F0ZWdvcmllcyIsIGZvbnQubGFiID0gMywgY29sLmxhYiA9ICJibHVlIiwgaG9yaXogPSBUUlVFKQoKIyBGb3IgbGluZXMgYW5kIGFuZ2xlczoKIyBkZW5zaXR5ID0gYygxMDAsMTAwLDEwMCwwLDEwMCksIGFuZ2xlID0gYygwLDAsOTAsMTEsMCkKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CmxpYnJhcnkocGxvdHJpeCkKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgQ2F0ZWdvcnkgbmFtZXMgKGxhYmVscyk6Cm5hbWVzIDwtIGMoIk5lZy4iLCAiTmV1dC4iLCAiUG9zLiIpCiMgQ2F0ZWdvcnkgcGVyY2VudGFnZXM6CnBlcmNlbnRhZ2UgPC0gcm91bmQodGFibGUodGVzdGluZyRTZW50aW1lbnQpIC8gbGVuZ3RoKHRlc3RpbmckU2VudGltZW50KSAqIDEwMCwgMikKIyBBZGRpbmcgdGhlIGZpcnN0IHBhcmVudGhlc2lzIHRvIHRoZSBsYWJlbHM6CmxibHMgPC0gcGFzdGUoIigiLCBuYW1lcywgc2VwID0gIiIpCiMgQWRkaW5nIHRoZSBzZWNvbmQgcGFyZW50aGVzaXMgYW5kIHRoZSBwZXJjZW50YWdlcyB0byBsYWJlbHM6CmxibHMgPC0gcGFzdGUobGJscywgcGVyY2VudGFnZSwgc2VwID0gIikgIikKIyBBZGRpbmcgdGhlICUgc3ltYm9scyB0byBsYWJlbHMKbGJscyA8LSBwYXN0ZShsYmxzLCIlIixzZXAgPSAiIikKCiMgQ3JlYXRpbmcgdGhlIHBpZSBjaGFydCB3aXRoIHRoZSBsYWJlbHMgYW5kIHBlcmNlbnRhZ2VzLCBhbmQgd2l0aCB0aGUgc2FtZSBjb2xvcnMgYXMgaW4gdGhlIGJhcnBsb3QuCnBpZTNEKHRhYmxlKHRlc3RpbmckU2VudGltZW50KSwgbGFiZWxzID0gbGJscywgZXhwbG9kZSA9IDAuMDUsIG1haW4gPSAiU2VudGltZW50J3MgZGlzdHJpYnV0aW9uIGluIHRoZSBUZXN0aW5nIGRhdGEgc2V0XG4ocGVyY2VudGFnZSkiLCBzdWIgPSAiUGllIENoYXJ0IG9mIGRpc3RyaWJ1dGlvbiIsIGNvbCA9IGNscnMyLCB0aGV0YSA9IDEuMiwgaGVpZ2h0ID0gMC4wMDUsIHN0YXJ0ID0gODYpCmBgYAoKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPkZhY3Rvcml6aW5nIHRoZSA8ZW0+U2VudGltZW50PC9lbT4gdmFyaWFibGUsIGFzc2lnbmluZyBudW1lcmljIHZhbHVlcyB0byB0aGUgcmVzdWx0aW5nIGZhY3RvcnMsIGFuZCBhZGRpbmcgdGhlbSB0byB0aGUgPHU+VGVzdGluZzwvdT4gZGF0YSBzZXQgYXMgYSBuZXcgY29sdW1uIG5hbWVkIDxlbT5MYWJlbHM8L2VtPjo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyfQp0ZXN0aW5nWyJMYWJlbHMiXSA8LSBhcy5pbnRlZ2VyKGFzLmZhY3Rvcih0ZXN0aW5nJFNlbnRpbWVudCkpIC0gMQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIHRoZSBmcmVxdWVuY3kgb2YgdGhlIDxlbT5MYWJlbHM8L2VtPiB2YXJpYWJsZSB3aXRoaW4gdGhlIDx1PlRlc3Rpbmc8L3U+IGRhdGEgc2V0Ojwvc3Ryb25nPjwvZm9udD4KYGBge3IgZWNobyA9IEZBTFNFfQp0YWJsZSh0ZXN0aW5nJExhYmVscykKYGBgCgo8ZGl2IHN0eWxlPSJjb2xvcjpibGFjaztiYWNrZ3JvdW5kLWNvbG9yOmxpZ2h0eWVsbG93Ij4KICAgPGJyPgogICA8Zm9udCBzaXplPSIrMC4zIj48c3BhbiBzdHlsZT0iY29sb3I6IGRhcmtibHVlIj5UaGUgZnJlcXVlbmN5IGNvdW50cyBvZiB0aGUgPHN0cm9uZz5MYWJlbHM8L3N0cm9uZz4gdmFyaWFibGUgZXhhY3RseSBtYXRjaCB0aG9zZSBvZiB0aGUgZnJlcXVlbmN5IG9mIHRoZSA8c3Ryb25nPlNlbnRpbWVudDwvc3Ryb25nPiBjb2x1bW4gaW4gdGhlIDx1PlRlc3Rpbmc8L3U+IGRhdGEgc2V0Ljwvc3Bhbj48L2ZvbnQ+CiAgIDxicj4KICAgPGJyPgo8L2Rpdj4KCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5DbGVhbmluZyBhbmQgdHJhbnNmb3JtaW5nIHRoZSA8dT50ZXh0PC91PiBvZiB0aGUgPGVtPk9yaWdpbmFsVHdlZXQ8L2VtPiB2YXJpYWJsZSBpbiB0aGUgPHU+VGVzdGluZzwvdT4gZGF0YSBzZXQ6PC9zdHJvbmc+PC9mb250PgpgYGB7ciB3YXJuaW5nID0gRkFMU0V9CnRlc3RpbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX25vbl9hc2NpaSh0ZXN0aW5nJE9yaWdpbmFsVHdlZXQpCnRlc3RpbmckT3JpZ2luYWxUd2VldCA8LSB0b2xvd2VyKHRlc3RpbmckT3JpZ2luYWxUd2VldCkKdGVzdGluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2VfZGF0ZSh0ZXN0aW5nJE9yaWdpbmFsVHdlZXQpCnRlc3RpbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX3RpbWUodGVzdGluZyRPcmlnaW5hbFR3ZWV0KQp0ZXN0aW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV9tb25leSh0ZXN0aW5nJE9yaWdpbmFsVHdlZXQpCnRlc3RpbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX251bWJlcih0ZXN0aW5nJE9yaWdpbmFsVHdlZXQpCnRlc3RpbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX2NvbnRyYWN0aW9uKHRlc3RpbmckT3JpZ2luYWxUd2VldCwgaWdub3JlLmNhc2UgPSBUUlVFKQoKdGVzdGluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2VfZ3JhZGUodGVzdGluZyRPcmlnaW5hbFR3ZWV0KQp0ZXN0aW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV9lbWFpbCh0ZXN0aW5nJE9yaWdpbmFsVHdlZXQpCnRlc3RpbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX2hhc2godGVzdGluZyRPcmlnaW5hbFR3ZWV0KQp0ZXN0aW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV90YWcodGVzdGluZyRPcmlnaW5hbFR3ZWV0KQp0ZXN0aW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV9odG1sKHRlc3RpbmckT3JpZ2luYWxUd2VldCkKdGVzdGluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2VfdXJsKHRlc3RpbmckT3JpZ2luYWxUd2VldCkKdGVzdGluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2VfaW50ZXJuZXRfc2xhbmcodGVzdGluZyRPcmlnaW5hbFR3ZWV0LCBpZ25vcmUuY2FzZSA9IFRSVUUpCnRlc3RpbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX2Vtb2ppKHRlc3RpbmckT3JpZ2luYWxUd2VldCkKdGVzdGluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2VfZW1vdGljb24odGVzdGluZyRPcmlnaW5hbFR3ZWV0KQoKdGVzdGluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlbW92ZVdvcmRzKHRlc3RpbmckT3JpZ2luYWxUd2VldCwgc3RvcHdvcmRzKCJlbmdsaXNoIikpCgp0ZXN0aW5nJE9yaWdpbmFsVHdlZXQgPC0gcmVwbGFjZV9zeW1ib2wodGVzdGluZyRPcmlnaW5hbFR3ZWV0KQoKdGVzdGluZyRPcmlnaW5hbFR3ZWV0IDwtIG1nc3ViKHRlc3RpbmckT3JpZ2luYWxUd2VldCwgIiciLCAiIikKCnRlc3RpbmckT3JpZ2luYWxUd2VldCA8LSBzdHJpcCh0ZXN0aW5nJE9yaWdpbmFsVHdlZXQpCnRlc3RpbmckT3JpZ2luYWxUd2VldCA8LSByZXBsYWNlX2tlcm4odGVzdGluZyRPcmlnaW5hbFR3ZWV0KQp0ZXN0aW5nJE9yaWdpbmFsVHdlZXQgPC0gd29yZFN0ZW0odGVzdGluZyRPcmlnaW5hbFR3ZWV0LCBsYW5ndWFnZSA9ICJlbmdsaXNoIikKdGVzdGluZyRPcmlnaW5hbFR3ZWV0IDwtIHJlcGxhY2Vfd2hpdGUodGVzdGluZyRPcmlnaW5hbFR3ZWV0KQoKdGVzdGluZyA8LSB0ZXN0aW5nWyEodGVzdGluZyRPcmlnaW5hbFR3ZWV0PT0gIiIpLCBdCmBgYAoKPCEtLSBPTkxZIHBlcmZvcm0gdGhpcyB0byBjaGVjayBpZiB0aGVyZSBhcmUgdGhpbmdzIHRoYXQgbmVlZCB0byBiZSBmaXhlZCBvciBpbXByb3ZlZCBhbmQKZG9uJ3QgZGlzcGxheSB0aGlzIGluIHRoZSBodG1sLiAtLT4KYGBge3IgZWNobyA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CiNjaGVja190ZXh0KHRlc3RpbmckT3JpZ2luYWxUd2VldCkKYGBgCgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+U2V0dGluZyB1cCBhIDx1PlZlY3RvciBTb3VyY2U8L3U+IHRvIHRyZWF0IGVhY2ggZWxlbWVudCBvZiB0aGUgPGVtPk9yaWdpbmFsVHdlZXQ8L2VtPiB2YXJpYWJsZSBpbiB0aGUgPHU+VGVzdGluZzwvdT4gZGF0YSBzZXQgYXMgaW5kaXZpZHVhbCBkb2N1bWVudHM6PC9zdHJvbmc+PC9mb250PgpgYGB7cn0KdGVzdGluZy52cyA8LSBWZWN0b3JTb3VyY2UodGVzdGluZyRPcmlnaW5hbFR3ZWV0KQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5DcmVhdGluZyBhIDx1PlZvbGF0aWxlIENvcnB1czwvdT4gZnJvbSB0aGUgPHU+VGVzdGluZzwvdT4gdmVjdG9yIHNvdXJjZTo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyfQp0ZXN0aW5nLnZjIDwtIFZDb3JwdXModGVzdGluZy52cykKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgRGVsZXRpbmcgdW51c2VkIGRhdGEgZnJhbWU6CnJtKHRlc3RpbmcudnMpCmBgYAoKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPkdlbmVyYXRpbmcgYSA8dT5Eb2N1bWVudC1UZXJtIE1hdHJpeDwvdT4gdXRpbGl6aW5nIHRoZSA8dT5UcmFpbmluZzwvdT4gRG9jdW1lbnQtVGVybSBNYXRyaXggYW5kIHRoZSA8dT5UZXN0aW5nPC91PiBWb2xhdGlsZSBDb3JwdXMuIFRoaXMgcHJvY2VzcyBlbnN1cmVzIHRoYXQgdGhlIHRlcm1zIGZvdW5kIGluIHRoZSA8dT5UcmFpbmluZzwvdT4gRG9jdW1lbnQtVGVybSBNYXRyaXggYXJlIG1pcnJvcmVkIGluIHRoZSA8dT5UZXN0aW5nPC91PiBEb2N1bWVudC1UZXJtIE1hdHJpeDo8L3N0cm9uZz48L2ZvbnQ+CjwhLS0gQ3JlYXRlcyBhIERvY3VtZW50LVRlcm0gTWF0cml4IGZyb20gdGhlIG5ldyBjb3JwdXMsIHVzaW5nIHRoZSB2b2NhYnVsYXJ5IGZyb20gdGhlIG9yaWdpbmFsIERUTS4gLS0+CmBgYHtyfQp0ZXN0X2R0bSA8LSBEb2N1bWVudFRlcm1NYXRyaXgodGVzdGluZy52YywgY29udHJvbCA9IGxpc3QoZGljdGlvbmFyeSA9IFRlcm1zKGR0bSkpKQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5TaG93aW5nIHRoZSBjb3VudCBvZiBkb2N1bWVudHMgYW5kIHRlcm1zIGluIGJvdGggRG9jdW1lbnQtVGVybSBNYXRyaWNlcyAobnVtYmVyIG9mIHRlcm1zIHNob3VsZCBiZSB0aGUgc2FtZSk6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgR2V0IHRoZSB0ZXJtcyAoY29sdW1uIG5hbWVzKSBmcm9tIGVhY2ggRFRNCnRyYWluaW5nLmR0bS50ZXJtcyA8LSBjb2xuYW1lcyhkdG0pCnRlc3RpbmcuZHRtLnRlcm1zIDwtIGNvbG5hbWVzKHRlc3RfZHRtKQoKIyBDaGVjayBpZiBib3RoIERUTXMgaGF2ZSB0aGUgc2FtZSBudW1iZXIgb2YgdGVybXMgKGNvbHVtbnMpCnRlcm1zX2NvdW50X21hdGNoIDwtIG5jb2woZHRtKSA9PSBuY29sKHRlc3RfZHRtKQoKY2F0KCJEVE0iLCAiXHRcdCIsICJEb2N1bWVudHMiLCAiXHQiLCAiVGVybXMiLCBlbmQgPSAiXG4iKQpjYXQoIltUcmFpbmluZ10iLCAiXHQiLCBucm93KGR0bSksICJcdFx0IiwgbmNvbChkdG0pLCBlbmQgPSAiXG4iKQpjYXQoIltUZXN0aW5nXSIsICJcdCIsIG5yb3codGVzdF9kdG0pLCAiXHRcdCIsIG5jb2wodGVzdF9kdG0pLCBlbmQgPSAiXG4iKQoKaWYgKHRlcm1zX2NvdW50X21hdGNoID09IEZBTFNFKXsKICBjYXQoIlxuIiwgIj4+PiBXQVJOSU5HOiBUaGUgbnVtYmVyIG9mIHRlcm1zIGFyZSBub3QgdGhlIHNhbWUhISEhISIpCn0gZWxzZSB7CiAgY2F0KCJcbiIsICI+Pj4gVGhlIG51bWJlciBvZiB0ZXJtcyBhcmUgdGhlIHNhbWUhISEhISIpCn0KYGBgCgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+UHJlc2VudGluZyB0aGUgbGlzdHMgb2YgdGVybXMgY29udGFpbmVkIHdpdGhpbiBib3RoIERvY3VtZW50LVRlcm0gTWF0cmljZXMgKHRoZSB0ZXJtcyBzaG91bGQgYmUgdGhlIHNhbWUpOjwvc3Ryb25nPjwvZm9udD4KYGBge3IgZWNobyA9IEZBTFNFfQojIENvbXBhcmUgdGhlIHRlcm1zIHRvIGVuc3VyZSB0aGV5IGFyZSBpZGVudGljYWwKdGVybXNfbWF0Y2ggPC0gYWxsKHNvcnQodHJhaW5pbmcuZHRtLnRlcm1zKSA9PSBzb3J0KHRlc3RpbmcuZHRtLnRlcm1zKSkKCnByaW50KGFzLmRhdGEuZnJhbWUoc29ydCh0cmFpbmluZy5kdG0udGVybXMpKSkKcHJpbnQoYXMuZGF0YS5mcmFtZShzb3J0KHRlc3RpbmcuZHRtLnRlcm1zKSkpCgppZiAodGVybXNfbWF0Y2ggPT0gRkFMU0UpewogIGNhdCgiPj4+IFdBUk5JTkc6IFRoZSB0ZXJtcyBhcmUgbm90IGlkZW50aWNhbCEhISEhIikKfSBlbHNlIHsKICBjYXQoIj4+PiBUaGUgdGVybXMgYXJlIGlkZW50aWNhbCEhISEhIikKfQpgYGAKCgoKCgoKCgoKCgoKCgo8YnI+Cjxicj4KPGZvbnQgc2l6ZT0iKzIiIGNvbG9yPSJuYXZ5Ij48c3Ryb25nPk1vZGVsIFRyYWluaW5nIGFuZCBFdmFsdWF0aW9uLjo8L3N0cm9uZz48L3NwYW4+PC9mb250Pgo8YnI+CjwhLS0gCgpOYWl2ZSBCYXllcyBDbGFzc2lmaWVyczoKClBhY2thZ2VzOiAiZTEwNzEiIGFuZCAibmFpdmViYXllcyIKCkZyb206IGh0dHBzOi8vbWVkaXVtLmNvbS9AZGFuY2Vyd29ybGQ2MC9kZW15c3RpZnlpbmctbmHDr3ZlLWJheWVzLWxvZy1wcm9iYWJpbGl0eS1hbmQtbGFwbGFjZS1zbW9vdGhpbmctZDZkYTYxYjBlNzBiCgpBbHNvIHNlZTogaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL25haXZlYmF5ZXMvdmlnbmV0dGVzL2ludHJvX25haXZlYmF5ZXMucGRmCgoKR2VuZXJhbCBOYWl2ZSBCYXllcyBmdW5jdGlvbjoKCiAgICBbImUxMDcxIl0KICAgIG5haXZlQmF5ZXMoZm9ybXVsYSwgZGF0YSwgbGFwbGFjZSA9IDAsIC4uLiwgc3Vic2V0LCBuYS5hY3Rpb24gPSBuYS5wYXNzKQoKICAgIFsibmFpdmViYXllcyJdCiAgICBuYWl2ZV9iYXllcyh4LCB5LCBwcmlvciA9IE5VTEwsIGxhcGxhY2UgPSAwLCB1c2VrZXJuZWwgPSBGQUxTRSwgdXNlcG9pc3NvbiA9IEZBTFNFLCAuLi4pCgoKMS4gR2F1c3NpYW4gTmFpdmUgQmF5ZXMgLSAgVGhpcyB0eXBlIG9mIE5haXZlIEJheWVzIGlzIHVzZWQgd2hlbiB0aGUgZGF0YXNldCBjb25zaXN0cyBvZiBudW1lcmljYWwgZmVhdHVyZXMuIEl0IGFzc3VtZXMgdGhhdCB0aGUgZmVhdHVyZXMgZm9sbG93IGEgR2F1c3NpYW4gKG5vcm1hbCkgZGlzdHJpYnV0aW9uLiBHYXVzc2lhbiBOYWl2ZSBCYXllcyBpcyBzdWl0YWJsZSBmb3IgY29udGludW91cyBkYXRhLiAoSXQncyBub3QgY29tbW9ubHkgdXNlZCBmb3IgdGV4dCBjbGFzc2lmaWNhdGlvbiB3aGVyZSBmZWF0dXJlcyBhcmUgdXN1YWxseSBkaXNjcmV0ZS4pCgoyLiBDYXRlZ29yaWNhbCBOYWl2ZSBCYXllcyAtIFdoZW4gdGhlIGRhdGFzZXQgY29udGFpbnMgY2F0ZWdvcmljYWwgZmVhdHVyZXMsIHN1Y2ggYXMgY29sb3JzIG9yIHR5cGVzIG9mIG9iamVjdHMsIHdlIHVzZSBDYXRlZ29yaWNhbCBOYWl2ZSBCYXllcy4gSXQgYXNzdW1lcyB0aGF0IGVhY2ggZmVhdHVyZSBmb2xsb3dzIGEgY2F0ZWdvcmljYWwgZGlzdHJpYnV0aW9uLiAoSXQncyBub3QgY29tbW9ubHkgdXNlZCBmb3IgdGV4dCBjbGFzc2lmaWNhdGlvbiB1bmxlc3MgdGhlIHRleHQgZmVhdHVyZXMgYXJlIGNvbnZlcnRlZCBpbnRvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4pCgozLiBCZXJub3VsbGkgTmFpdmUgQmF5ZXMgLSBCZXJub3VsbGkgTmFpdmUgQmF5ZXMgaXMgYXBwbGllZCB3aGVuIHRoZSBmZWF0dXJlcyBhcmUgYmluYXJ5IG9yIGZvbGxvdyBhIEJlcm5vdWxsaSBkaXN0cmlidXRpb24uIFRoaXMgdHlwZSBvZiBOYWl2ZSBCYXllcyBpcyBzdWl0YWJsZSBmb3IgZGF0YXNldHMgd2l0aCBiaW5hcnkgZmVhdHVyZXMgbGlrZSBwcmVzZW5jZSBvciBhYnNlbmNlIG9mIGNlcnRhaW4gYXR0cmlidXRlcy4gKEl0J3MgY29tbW9ubHkgdXNlZCBmb3IgdGV4dCBjbGFzc2lmaWNhdGlvbiB0YXNrcywgZXNwZWNpYWxseSB3aGVuIHJlcHJlc2VudGluZyB0ZXh0IGRhdGEgdXNpbmcgYmluYXJ5IHRlcm0gcHJlc2VuY2UvYWJzZW5jZSB2ZWN0b3JzLikKCjQuIE11bHRpbm9taWFsIE5haXZlIEJheWVzIC0gTXVsdGlub21pYWwgTmFpdmUgQmF5ZXMgaXMgY29tbW9ubHkgdXNlZCBmb3IgdGV4dCBjbGFzc2lmaWNhdGlvbiB0YXNrcy4gSXQgYXNzdW1lcyB0aGF0IGZlYXR1cmVzIHJlcHJlc2VudCB0aGUgZnJlcXVlbmNpZXMgb3Igb2NjdXJyZW5jZXMgb2YgZGlmZmVyZW50IHdvcmRzIGluIHRoZSB0ZXh0LiBJdCBpcyBzdWl0YWJsZSBmb3IgZGF0YXNldHMgd2l0aCBkaXNjcmV0ZSBmZWF0dXJlcyBhbmQgZm9sbG93cyBhIG11bHRpbm9taWFsIGRpc3RyaWJ1dGlvbi4gKEl0J3Mgb25lIG9mIHRoZSBNT1NUIENPTU1PTkxZIHVzZWQgY2xhc3NpZmllcnMgZm9yIHRleHQgY2xhc3NpZmljYXRpb24gdGFza3MuKQoKICAgIFsibmFpdmViYXllcyJdCiAgICBtdWx0aW5vbWlhbF9uYWl2ZV9iYXllcyh4LCB5LCBwcmlvciA9IE5VTEwsIGxhcGxhY2UgPSAwLjUsIC4uLikKICAgICAgICBOb3RlOiB4IGhhcyB0byBiZSBhIE1hdHJpeC4KICAgICAgICBOb3RlOiB5IGhhcyB0byBiZSBhIGNsYXNzIHZlY3RvciAoY2hhcmFjdGVyL2ZhY3Rvci9sb2dpY2FsKS4KICAgICAgICBOb3RlOiBsYXBsYWNlIGhhcyB0aGUgZGVmYXVsdCBudW1iZXIgb2YgMC41LgoKNS4gQ29tcGxlbWVudCBOYWl2ZSBCYXllcyAtICBDb21wbGVtZW50IE5haXZlIEJheWVzIGlzIGEgdmFyaWF0aW9uIG9mIE5haXZlIEJheWVzIHRoYXQgaXMgZGVzaWduZWQgdG8gYWRkcmVzcyBpbWJhbGFuY2VkIGRhdGFzZXRzLiBJdCBpcyBwYXJ0aWN1bGFybHkgdXNlZnVsIHdoZW4gdGhlIG1ham9yaXR5IGNsYXNzIG92ZXJ3aGVsbXMgdGhlIG1pbm9yaXR5IGNsYXNzIGluIHRoZSBkYXRhc2V0LiBJdCBhaW1zIHRvIGNvcnJlY3QgdGhlIGltYmFsYW5jZSBieSBjb25zaWRlcmluZyB0aGUgY29tcGxlbWVudCBvZiBlYWNoIGNsYXNzIHdoZW4gbWFraW5nIHByZWRpY3Rpb25zLiAoSXQncyB1c2VmdWwgd2hlbiBkZWFsaW5nIHdpdGggaW1iYWxhbmNlZCB0ZXh0IGNsYXNzaWZpY2F0aW9uIGRhdGFzZXRzLikKCi0tPgoKYGBge3IgZWNobyA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CmxpYnJhcnkobmFpdmViYXllcykKYGBgCgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+PHU+VHJhaW5pbmc8L3U+IGEgTXVsdGlub21pYWwgTmFpdmUgQmF5ZXMgbW9kZWwgb24gdGhlIHRyYWluaW5nIGRhdGE6PC9zdHJvbmc+PC9mb250PgpgYGB7cn0KIyBUcmFpbiB0aGUgTmHDr3ZlIEJheWVzIG1vZGVsIG9uIHRoZSB0cmFpbmluZyBkYXRhLAptdWx0aW5vbWlhbC5uYWl2ZS5iYXllcy5tb2RlbCA8LSBtdWx0aW5vbWlhbF9uYWl2ZV9iYXllcyhhcy5tYXRyaXgoZHRtKSwgYXMuZmFjdG9yKHRyYWluaW5nJExhYmVscyksIGxhcGxhY2UgPSAxKQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5HZXR0aW5nIHRoZSA8dT5wcmVkaWN0aW9uczwvdT4gb2YgdGhlIG1vZGVsIG9uIHRoZSB0ZXN0aW5nIGRhdGE6PC9zdHJvbmc+PC9mb250PgpgYGB7cn0KIyBHZXR0aW5nIHRoZSBwcmVkaWN0aW9ucyBvZiB0aGUgTmHDr3ZlIG1vZGVsIG9uIHRoZSB2YWxpZGF0aW9uIGRhdGEuCm11bHRpbm9taWFsLm5haXZlLmJheWVzLnByZWRpY3Rpb25zIDwtIHByZWRpY3QobXVsdGlub21pYWwubmFpdmUuYmF5ZXMubW9kZWwsIG5ld2RhdGEgPSBhcy5tYXRyaXgodGVzdF9kdG0pKQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIHRoZSA8dT5hY2N1cmFjeTwvdT4gb2YgdGhlIG1vZGVsOjwvc3Ryb25nPjwvZm9udD4KYGBge3IgZWNobyA9IEZBTFNFfQojIEV2YWx1YXRpbmcgbW9kZWwgYWNjdXJhY3kKIwojIFN0b3JpbmcgdGhlIG51bWJlciBvZiBwcmVkaWN0aW9ucyBtYWRlIGJ5IHRoZSBOYcOvdmUgQmF5ZXMgbW9kZWwuCnRvdGFsX3ByZWRpY3Rpb25zIDwtIGxlbmd0aChtdWx0aW5vbWlhbC5uYWl2ZS5iYXllcy5wcmVkaWN0aW9ucykKCiMgQ2FsY3VsYXRpbmcgdGhlIGFtb3VudCBvZiBjb3JyZWN0IHByZWRpY3Rpb25zIG1hZGUgYnkgdGhlIE5hw692ZSBCYXllcyBtb2RlbC4KY29ycmVjdF9wcmVkaWN0aW9ucyA8LSBzdW0obXVsdGlub21pYWwubmFpdmUuYmF5ZXMucHJlZGljdGlvbnMgPT0gdGVzdGluZyRMYWJlbHMpCgojIE9idGFpbmluZyB0aGUgYWNjdXJhY3kgb2YgdGhlIE5hw692ZSBCYXllcyBtb2RlbCdzIHByZWRpY3Rpb25zLgpuYWl2ZS5hY2N1cmFjeSA8LSAoY29ycmVjdF9wcmVkaWN0aW9ucyAvIHRvdGFsX3ByZWRpY3Rpb25zKSAqIDEwMAoKIyBEaXNwbGF5aW5nIHRoZSBhY2N1cmFjeQpjYXQoIkFjY3VyYWN5OiAiLCByb3VuZChuYWl2ZS5hY2N1cmFjeSwgMiksICIlIiwgc2VwID0gIiIpCmBgYAoKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPlNob3dpbmcgdGhlIGNvdW50IG9mIHRoZSA8dT5pbmNvcnJlY3QgcHJlZGljdGlvbnMgbGFiZWxzPC91PiBvZiB0aGUgbW9kZWw6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CmluY29ycmVjdC5wcmVkaWN0aW9ucyA8LSBzdW0odGVzdGluZyRMYWJlbHMgIT0gbXVsdGlub21pYWwubmFpdmUuYmF5ZXMucHJlZGljdGlvbnMpCgpjYXQoIkFtb3VudCBvZiBpbmNvcnJlY3QgcHJlZGljdGlvbnM6IiwgaW5jb3JyZWN0LnByZWRpY3Rpb25zKQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIGEgbGlzdCBvZiB0aGUgPHU+YWN0dWFsIGxhYmVsczwvdT4gbmV4dCB0byA8dT5pbmNvcnJlY3QgcHJlZGljdGlvbnMgbGFiZWxzPC91PiBvZiB0aGUgbW9kZWw6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgQSBtYXRyaXggdG8gaG9sZCBhbGwgaW5jb3JyZWN0IHByZWRpY3Rpb25zLgppbmNvcnJlY3QudmFsdWVzLm1hdHJpeCA8LSBtYXRyaXgoTkEsIG5yb3cgPSBpbmNvcnJlY3QucHJlZGljdGlvbnMsIG5jb2wgPSAyKQoKY291bnRlciA8LSAwCmZvciAoaSBpbiAxOmxlbmd0aCh0ZXN0aW5nJExhYmVscykpewogICAgaWYodGVzdGluZyRMYWJlbHNbaV0gIT0gbXVsdGlub21pYWwubmFpdmUuYmF5ZXMucHJlZGljdGlvbnNbaV0pewogICAgICAgIGNvdW50ZXIgPSBjb3VudGVyICsgMQogICAgICAgIGluY29ycmVjdC52YWx1ZXMubWF0cml4W2NvdW50ZXIsMV0gPC0gdGVzdGluZyRMYWJlbHNbaV0KICAgICAgICBpbmNvcnJlY3QudmFsdWVzLm1hdHJpeFtjb3VudGVyLDJdIDwtIG11bHRpbm9taWFsLm5haXZlLmJheWVzLnByZWRpY3Rpb25zWzFdCiAgICB9Cn0KCiMgQ29udmVydCB0aGUgbWF0cml4IHRvIGEgZGF0YSBmcmFtZQppbmNvcnJlY3RWYWx1ZXMuZGYgPC0gYXMuZGF0YS5mcmFtZShpbmNvcnJlY3QudmFsdWVzLm1hdHJpeCkKCiMgU2V0IGNvbHVtbiBuYW1lcwpjb2xuYW1lcyhpbmNvcnJlY3RWYWx1ZXMuZGYpIDwtIGMoIkFjdHVhbCIsICJQcmVkaWN0ZWQiKQoKaW5jb3JyZWN0VmFsdWVzLmRmCmBgYAoKPGJyPgo8Zm9udCBzaXplPSIrMCIgY29sb3I9ImJsYWNrIj48c3Ryb25nPlByZXNlbnRpbmcgYSBmcmVxdWVuY3kgdGFibGUgb2YgdGhlIDx1PmFjdHVhbCBsYWJlbHM8L3U+IG9mIHRoZSA8dT5UZXN0aW5nPC91PiBkYXRhIHNldDo8L3N0cm9uZz48L2ZvbnQ+CmBgYHtyIGVjaG8gPSBGQUxTRX0KY2F0KCJBY3R1YWwgbGFiZWxzIHRhYmxlOiIsIGVuZD0iXG4iKQp0YWJsZSh0ZXN0aW5nJExhYmVscykKYGBgCgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+U2hvd2luZyBhIGZyZXF1ZW5jeSB0YWJsZSBvZiB0aGUgPHU+cHJlZGljdGlvbnMgbGFiZWxzPC91PiBvZiB0aGUgbW9kZWw6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CmNhdCgiUHJlZGljdGlvbnMgbGFiZWxzIHRhYmxlOiIsIGVuZD0iXG5cbiIpCnRhYmxlKG11bHRpbm9taWFsLm5haXZlLmJheWVzLnByZWRpY3Rpb25zKQpgYGAKCjxicj4KPGZvbnQgc2l6ZT0iKzAiIGNvbG9yPSJibGFjayI+PHN0cm9uZz5EaXNwbGF5aW5nIGEgPHU+Q29uZnVzaW9uIE1hdHJpeDwvdT4gb2YgdGhlIDx1PmFjdHVhbCBsYWJlbHM8L3U+IG9mIHRoZSA8dT5UZXN0aW5nPC91PiBkYXRhIHNldCB2cyB0aGUgPHU+cHJlZGljdGlvbnMgbGFiZWxzPC91PiBvZiB0aGUgbW9kZWw6PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgTm90ZTogaWYgdGhlIHByZWRpY3Rpb25zIGVuZCB1cCBiZWluZyBvZiBvbmx5IG9uZSBjbGFzcywgeW91ciBDb25mdXNpb24gTWF0cml4IHdpbGwgc2hvdyBvbmx5CiMgb25lIGNvbHVtbi4gVGhlIHNhbWUgY2FuIGhhcHBlbnMgd2l0aCB0aGUgcm93cy4KIwojIFJvd3MgcmVwcmVzZW50IHRoZSBsZXZlbHMgb3IgY2F0ZWdvcmllcyBvZiB0aGUgdmFyaWFibGUgdGVzdGluZyRMYWJlbHMuCiMgQ29sdW1ucyByZXByZXNlbnQgdGhlIGxldmVscyBvciBjYXRlZ29yaWVzIG9mIHRoZSB2YXJpYWJsZSBtdWx0aW5vbWlhbC5uYWl2ZS5iYXllcy5wcmVkaWN0aW9ucwojCmNvbmZfbWF0cml4IDwtIHRhYmxlKHRlc3RpbmckTGFiZWxzLCBtdWx0aW5vbWlhbC5uYWl2ZS5iYXllcy5wcmVkaWN0aW9ucykKCiMgU2V0cyB0aGUgY3VzdG9tIG5hbWVzIGZvciByb3dzIGFuZCBjb2x1bW5zCmN1c3RvbV9uYW1lcyA8LSBjKCIoUHJlZCBOZWcpIDAiLCAiKFByZWQgTmV1KSAxIiwgIihQcmVkIFBvcykgMiIpCmNvbG5hbWVzKGNvbmZfbWF0cml4KSA8LSBjdXN0b21fbmFtZXMKCmN1c3RvbV9uYW1lcyA8LSBjKCIoVHJ1ZSBOZWcpIDAiLCAiKFRydWUgTmV1KSAxIiwgIihUcnVlIFBvcykgMiIpCnJvd25hbWVzKGNvbmZfbWF0cml4KSA8LSBjdXN0b21fbmFtZXMKCmNhdCgiQ29uZnVzaW9uIE1hdHJpeDoiLCBlbmQ9IlxuXG4iKQpwcmludChjb25mX21hdHJpeCkKIyBUUlVFLU5lZ2F0aXZlICAgICBGYWxzZS1OZXV0cmFsICAgICBGYWxzZS1Qb3NpdGl2ZQojIEZhbHNlLU5lZ2F0aXZlICAgIFRSVUUtTmV1dHJhbCAgICAgIEZhbHNlLVBvc2l0aXZlCiMgRmFsc2UtTmVnYXRpdmUgICAgRmFsc2UtTmV1dHJhbCAgICAgVFJVRS1Qb3NpdGl2ZQoKYGBgCgo8YnI+Cjxmb250IHNpemU9IiswIiBjb2xvcj0iYmxhY2siPjxzdHJvbmc+UHJlc2VudGluZyBhIDx1PlByb3BvcnRpb24gQ29uZnVzaW9uIE1hdHJpeDwvdT4gY29tcGFyaW5nIHRoZSB0b3RhbCBjb3VudCBvZiB0aGUgPHU+YWN0dWFsIGxhYmVsczwvdT4gZnJvbSB0aGUgPHU+VGVzdGluZzwvdT4gZGF0YSBzZXQgYWdhaW5zdCB0aGUgPHU+cHJlZGljdGVkIGxhYmVsczwvdT4gZ2VuZXJhdGVkIGJ5IHRoZSBtb2RlbC46PC9zdHJvbmc+PC9mb250PgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgTm90ZTogaWYgdGhlIHByZWRpY3Rpb25zIGVuZCB1cCBiZWluZyBvZiBvbmx5IG9uZSBjbGFzcywgeW91ciBDb25mdXNpb24gTWF0cml4IHdpbGwgc2hvdyBvbmx5CiMgb25lIGNvbHVtbi4gVGhlIHNhbWUgY2FuIGhhcHBlbnMgd2l0aCB0aGUgcm93cy4KIwojIFJvd3MgcmVwcmVzZW50IHRoZSBsZXZlbHMgb3IgY2F0ZWdvcmllcyBvZiB0aGUgdmFyaWFibGUgdGVzdGluZyRMYWJlbHMuCiMgQ29sdW1ucyByZXByZXNlbnQgdGhlIGxldmVscyBvciBjYXRlZ29yaWVzIG9mIHRoZSB2YXJpYWJsZSBtdWx0aW5vbWlhbC5uYWl2ZS5iYXllcy5wcmVkaWN0aW9ucwojCmNvbmZfbWF0cml4IDwtIHByb3AudGFibGUodGFibGUodGVzdGluZyRMYWJlbHMsIG11bHRpbm9taWFsLm5haXZlLmJheWVzLnByZWRpY3Rpb25zKSkKCiMgU2V0cyB0aGUgY3VzdG9tIG5hbWVzIGZvciByb3dzIGFuZCBjb2x1bW5zCmN1c3RvbV9uYW1lcyA8LSBjKCIoUHJlZCBOZWcpIDAiLCAiKFByZWQgTmV1KSAxIiwgIihQcmVkIFBvcykgMiIpCmNvbG5hbWVzKGNvbmZfbWF0cml4KSA8LSBjdXN0b21fbmFtZXMKCmN1c3RvbV9uYW1lcyA8LSBjKCIoVHJ1ZSBOZWcpIDAiLCAiKFRydWUgTmV1KSAxIiwgIihUcnVlIFBvcykgMiIpCnJvd25hbWVzKGNvbmZfbWF0cml4KSA8LSBjdXN0b21fbmFtZXMKCmNhdCgiUHJvcG9ydGlvbiBDb25mdXNpb24gTWF0cml4OiIsIGVuZD0iXG5cbiIpCnByaW50KGNvbmZfbWF0cml4KQojIFRSVUUtTmVnYXRpdmUgICAgIEZhbHNlLU5ldXRyYWwgICAgIEZhbHNlLVBvc2l0aXZlCiMgRmFsc2UtTmVnYXRpdmUgICAgVFJVRS1OZXV0cmFsICAgICAgRmFsc2UtUG9zaXRpdmUKIyBGYWxzZS1OZWdhdGl2ZSAgICBGYWxzZS1OZXV0cmFsICAgICBUUlVFLVBvc2l0aXZlCgpgYGAKCjxkaXYgc3R5bGU9ImNvbG9yOmJsYWNrO2JhY2tncm91bmQtY29sb3I6bGlnaHR5ZWxsb3ciPgogICA8YnI+CiAgIDxmb250IHNpemU9IiswLjMiPjxzcGFuIHN0eWxlPSJjb2xvcjogZGFya2JsdWUiPkJhc2VkIG9uIHRoZSBDb25mdXNpb24gTWF0cmljZXMsIDxzdHJvbmc+MjQ1MDwvc3Ryb25nPiBvZiB0aGUgcHJlZGljdGlvbnMgd2VyZSA8c3Ryb25nPmNvcnJlY3RseSBsYWJlbGVkPC9zdHJvbmc+LCBhY2NvdW50aW5nIGZvciA8c3Ryb25nPjY0LjUyJTwvc3Ryb25nPiBvZiBhbGwgcHJlZGljdGlvbnMuIFRoZXNlIGZpbmRpbmdzIGNvcnJvYm9yYXRlIHByZXZpb3VzIGRhdGEgZnJvbSB0aGlzIHN0dWR5LiBTdWJ0cmFjdGluZyAyNDUwIGZyb20gdGhlIHRvdGFsIHByZWRpY3Rpb25zIG1hZGUgKDM3OTcpIHlpZWxkcyAxMzQ3ICh0aGUgbnVtYmVyIG9mIGluY29ycmVjdCBwcmVkaWN0aW9ucyBjYWxjdWxhdGVkIHByZXZpb3VzbHkpLCBhbmQgdGhlIHBlcmNlbnRhZ2Ugb2J0YWluZWQgZnJvbSB0aGUgQ29uZnVzaW9uIE1hdHJpY2VzIHByZWNpc2VseSBtYXRjaGVzIHRoZSBhY2N1cmFjeSBwZXJjZW50YWdlIG9mIHRoZSBtb2RlbCAod2l0aG91dCByb3VuZGluZykuPC9zcGFuPjwvZm9udD4KICAgPGJyPgogICA8YnI+CiAgIDxmb250IHNpemU9IiswLjMiPjxzcGFuIHN0eWxlPSJjb2xvcjogZGFya2JsdWUiPk9mIHRoZSBpbmNvcnJlY3RseSBwcmVkaWN0ZWQgdmFsdWVzLCBpdCBhcHBlYXJzIHRoYXQgdGhlIG1vZGVsIDxzdHJvbmc+bWlzbGFiZWxlZDwvc3Ryb25nPiBtb3JlIDxzdHJvbmc+TmVnYXRpdmUgdmFsdWVzIGFzIFBvc2l0aXZlIGFuZCB2aWNlIHZlcnNhPC9zdHJvbmc+LiBTcGVjaWZpY2FsbHksIDMzMyBOZWdhdGl2ZSB2YWx1ZXMgd2VyZSBsYWJlbGVkIGFzIFBvc2l0aXZlLCBjb25zdGl0dXRpbmcgYXBwcm94aW1hdGVseSA4Ljc3JSBvZiBhbGwgcHJlZGljdGlvbnMuIFRoaXMgd2FzIGNsb3NlbHkgZm9sbG93ZWQgYnkgMzI2IFBvc2l0aXZlIHZhbHVlcyBsYWJlbGVkIGFzIE5lZ2F0aXZlLCByZXByZXNlbnRpbmcgYXJvdW5kIDguNTklIG9mIGFsbCBwcmVkaWN0aW9ucy48L3NwYW4+PC9mb250PgogICA8YnI+CiAgIDxicj4KICAgPGZvbnQgc2l6ZT0iKzAuMyI+PHNwYW4gc3R5bGU9ImNvbG9yOiBkYXJrYmx1ZSI+PHN0cm9uZz5Ob3RlOjwvc3Ryb25nPiBVc2UgdGhlIGZvbGxvd2luZyB0YWJsZSBmb3IgdGhlIENvbmZ1c2lvbiBNYXRyaWNlcyBpbnRlcnByZXRhdGlvbi48L3NwYW4+PC9mb250PgogICA8YnI+CiAgIDxicj4KICAgPGZvbnQgc2l6ZT0iKzAuMyI+PHNwYW4gc3R5bGU9ImNvbG9yOiBkYXJrYmx1ZSI+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7VHJ1ZS1OZWdhdGl2ZSZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwO0ZhbHNlLU5ldXRyYWwmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDtGYWxzZS1Qb3NpdGl2ZTwvc3Bhbj48L2ZvbnQ+CiAgIDxicj4KICAgPGZvbnQgc2l6ZT0iKzAuMyI+PHNwYW4gc3R5bGU9ImNvbG9yOiBkYXJrYmx1ZSI+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7RmFsc2UtTmVnYXRpdmUmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDtUcnVlLU5ldXRyYWwmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDtGYWxzZS1Qb3NpdGl2ZTwvc3Bhbj48L2ZvbnQ+CiAgIDxicj4KICAgPGZvbnQgc2l6ZT0iKzAuMyI+PHNwYW4gc3R5bGU9ImNvbG9yOiBkYXJrYmx1ZSI+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7RmFsc2UtTmVnYXRpdmUmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDtGYWxzZS1OZXV0cmFsJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7VHJ1ZS1Qb3NpdGl2ZTwvc3Bhbj48L2ZvbnQ+CjwvZGl2Pg==