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&amp;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==