1 Project Scope

The goal of this assignment is give you practice working with accuracy and other recommender system metrics. Choose a different dataset to work with from your previous projects.

Deliverables 1. As in your previous assignments, compare the accuracy of at least two recommender system algorithms against your offline data. 2. Implement support for at least one business or user experience goal such as increased serendipity, novelty, or diversity. 3. Compare and report on any change in accuracy before and after you’ve made the change in #2. 4. As part of your textual conclusion, discuss one or more additional experiments that could be performed and/or metrics that could be evaluated only if online evaluation was possible. Also, briefly propose how you would design a reasonable online evaluation environment.

2 Introduction

For this project, I chose Jester5K dataset. The project will

  • Explore the Jester5K dataset
  • Compare the UCBF, Popular, Random, and Hybrid recommender
  • Discuss a reasonable online evaluation

2.1 Data Exploration - Jester 5K dataset

The Jester 5K dataset is a dataset consisting of 5000 users rating 100 of jokes which means a combination of 500,000 users and ratings.

## 5000 x 100 rating matrix of class 'realRatingMatrix' with 362106 ratings.

Jester5K has a slot for the data. Looking at this slot, we see that the data slot of Jester5K is of the class dgcMatrix.

## [1] "data"      "normalize"
## [1] "dgCMatrix"
## attr(,"package")
## [1] "Matrix"

2.1.1 The Jokes

Each column in the dataset represents a joke for a total of 100 jokes.

## [1] 100

The columns contain the names of the jokes. Below are the first five column names and below that is the text for each of these jokes.

## [1] "j1" "j2" "j3" "j4" "j5"
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          j95 
##                                                                                                                                                                                                                                                                                                                                                  "Just a thought .. Before criticizing someone, walk a mile in their shoes. Then when you do criticize them, you will be a mile away and have their shoes !" 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          j96 
##                                                                                                                                                                "Two attorneys went into a diner and ordered two drinks. Then they produced sandwiches from their briefcases and started to eat. The owner became quite concerned and marched over and told them, \"You can't eat your own sandwiches in here!\" The attorneys looked at each other, shrugged their shoulders and then exchanged sandwiches." 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          j97 
##                                                                     "A teacher is explaining to her class how different languages use negatives differently. She says, \"In all languages, a positive followed by a negative or a negative followed by a positive makes a negative. In some languages, two negatives together make a positive, while in others they make a negative. But in no language do two positives make a negative.\" One of the students puts up his hand and says, \"Yeah, right.\"" 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          j98 
## "Age and Womanhood 1. Between the ages of 13 and 18 ... She is like Africa, virgin and unexplored. 2. Between the ages of 19 and 35 ... She is like Asia, hot and exotic. 3. Between the ages of 36 and 45 ... She is like America, fully explored, breathtakingly beautiful,and free with her resources. 4. Between the ages of 46 and 56 ... She is like Europe, exhausted but still has points of interest. 5. After 56 she is like Australia ... Everybody knows it's down there, but who gives a damn?" 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          j99 
##                                                                                                                                                                                                                                                                                                                                                                                            "A bus station is where a bus stops. A train station is where a train stops. On my desk I have a work station..." 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         j100 
##                                                                                                                                                                                                                                                                                                                                                  "Q: Whats the difference between greeting a Queen and greeting the President of the United States? A: You only have to get on one knee to greet the queen."

2.1.2 The user ratings

The dataset contains a totak of 362,106 ratings which means that the dataset is dense aprrox. 72% full.

## [1] 362106

The ratings of the jokes range from a -9.95 to a positive 9.9 with an average rating of 0.8525. This result is after removing entries without a “0” rating.

## [1] -9.95  9.90
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -9.9500 -3.0600  1.4600  0.8525  5.1000  9.9000

From this visualization, we see that jokes rated from 3 to 4 on a scale of -10 to 10, were the most commonly rated joke. Overall, more jokes are rated positively than negatively.

2.2 Most rated Jokes

##   jokes told
## 1    j8 5000
## 2   j13 5000
## 3   j15 5000
##                                                                                  j8 
## "Q. Did you hear about the dyslexic devil worshiper? A. He sold his soul to Santa."
##                                                                                                    j13 
## "They asked the Japanese visitor if they have elections in his country. \"Every Morning\" he answers."
##                                                                                    j15 
## "Q: What did the blind person say when given some matzah? A: Who the hell wrote this?"

2.3 Binarize vs. Normalize

The goal of this project is to compare recommender models accounting for finding novel or serendipitous recommendations. If I binarize the data, then I lose the granualarity of the recommendation. All that I would be able to tell would be that the user rated the joke, not how well or highly rated.

Normalizing the data seems to be the better approach given the wide range of the data.

First, I defined a minimum number of 99 users who have rated at least 25 jokes.

## 1422 x 100 rating matrix of class 'realRatingMatrix' with 142200 ratings.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Normalizing the Jokes

## [1] 0

2.4 User Similarity

In the blocks below, I used RecommenderLab’s similarity function to find similarity among the top 50 users. The more red blocks indicates similarity between the users. This small sample tells us that there is some similarities between the users but not very strong.

3 Comparing Collaboration Filtering Models - UBCF and IBCF

In this section, I applied the UBCF and IBCF algorithms to the Jester dataset. For Serendipity, I then applied the POPULAR algorithm.

3.2 Evaluation of models

To evaluate the two models, I created a list of UBCF and SVD models with different parameters (pearson and cosine). This list was fed into the evaluate function and below. The visualizations below both show that the UBCF using the “pearson” method had the larger area under the curve.

In conclusion, this project has shown that if we want our model to be more precise with its recommendations, we would choose the UBCF model and recommend five or less movies. If the number of recommendations is 50 or above, then the UBCF-pearson model does not perform better than the other models.

## UBCF run fold/sample [model time/prediction time]
##   1  [0.04sec/0.26sec] 
##   2  [0.01sec/0.38sec] 
##   3  [0.02sec/0.27sec] 
##   4  [0.02sec/0.28sec] 
##   5  [0.01sec/0.27sec] 
##   6  [0.01sec/0.4sec] 
## UBCF run fold/sample [model time/prediction time]
##   1  [0sec/0.26sec] 
##   2  [0.02sec/0.29sec] 
##   3  [0.02sec/0.28sec] 
##   4  [0.02sec/0.27sec] 
##   5  [0sec/0.31sec] 
##   6  [0.01sec/0.28sec] 
## IBCF run fold/sample [model time/prediction time]
##   1  [0.06sec/0.05sec] 
##   2  [0.06sec/0.04sec] 
##   3  [0.05sec/0.03sec] 
##   4  [0.05sec/0.05sec] 
##   5  [0.06sec/0.05sec] 
##   6  [0.04sec/0.04sec] 
## IBCF run fold/sample [model time/prediction time]
##   1  [0.07sec/0.03sec] 
##   2  [0.08sec/0.03sec] 
##   3  [0.08sec/0.03sec] 
##   4  [0.08sec/0.03sec] 
##   5  [0.08sec/0.03sec] 
##   6  [0.07sec/0.04sec]

## integer(0)

3.2.1 Serendipity

To account for serendipity, I added and evaluated the POPULAR model without any parameters. We see that this model performs as well as the UBCF models and outperforms the IBCF model.

## $normalize
## [1] "center"
## 
## $aggregationRatings
## standardGeneric for "colMeans" defined from package "base"
## 
## function (x, na.rm = FALSE, dims = 1, ...) 
## standardGeneric("colMeans")
## <bytecode: 0x00000000234a3960>
## <environment: 0x000000001b1dd280>
## Methods may be defined for arguments: x
## Use  showMethods("colMeans")  for currently available ones.
## 
## $aggregationPopularity
## standardGeneric for "colSums" defined from package "base"
## 
## function (x, na.rm = FALSE, dims = 1, ...) 
## standardGeneric("colSums")
## <bytecode: 0x000000002348e658>
## <environment: 0x000000001b3354e8>
## Methods may be defined for arguments: x
## Use  showMethods("colSums")  for currently available ones.
## UBCF run fold/sample [model time/prediction time]
##   1  [0.02sec/0.26sec] 
##   2  [0sec/0.29sec] 
##   3  [0.01sec/0.28sec] 
##   4  [0.01sec/0.38sec] 
##   5  [0.01sec/0.27sec] 
##   6  [0.02sec/0.23sec] 
## UBCF run fold/sample [model time/prediction time]
##   1  [0sec/0.27sec] 
##   2  [0.02sec/0.28sec] 
##   3  [0.02sec/0.27sec] 
##   4  [0.01sec/0.39sec] 
##   5  [0sec/0.28sec] 
##   6  [0.02sec/0.28sec] 
## IBCF run fold/sample [model time/prediction time]
##   1  [0.18sec/0.03sec] 
##   2  [0.06sec/0.03sec] 
##   3  [0.07sec/0.03sec] 
##   4  [0.06sec/0.02sec] 
##   5  [0.07sec/0.03sec] 
##   6  [0.06sec/0.03sec] 
## IBCF run fold/sample [model time/prediction time]
##   1  [0.08sec/0.03sec] 
##   2  [0.06sec/0.03sec] 
##   3  [0.09sec/0.03sec] 
##   4  [0.09sec/0.03sec] 
##   5  [0.08sec/0.03sec] 
##   6  [0.08sec/0.03sec] 
## POPULAR run fold/sample [model time/prediction time]
##   1  [0sec/0.37sec] 
##   2  [0.02sec/0.26sec] 
##   3  [0sec/0.25sec] 
##   4  [0sec/0.25sec] 
##   5  [0sec/0.27sec] 
##   6  [0.02sec/0.25sec]

## integer(0)

4 Conclusion

On the basis of AOC, Precision/Recall, and the RMSE, the POPULAR model outperforms the RANDOM model. IOW, populars jokes are rated higher by users than a random selection of jokes. Another experiment that could be run would be A/B testing. For example, lets say that you have an online streaming music service. This service would deploy two recommender models and based on whether the users actually select the songs and rate them would give you the best evaluation.

To conclude, let’s look at a few of the jokes the POPULAR model recommended.

##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             j50 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  "A guy goes into confession and says to the priest, \"Father, I'm 80 years old, widower, with 11 grandchildren. Last night I met two beautiful flight attendants. They took me home and I made love to both of them. Twice.\" The priest said: \"Well, my son, when was the last time you were in confession?\" \"Never Father, I'm Jewish.\" \"So then, why are you telling me?\" \"I'm telling everybody.\"" 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             j32 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               "A man arrives at the gates of heaven. St. Peter asks, \"Religion?\" The man says, \"Methodist.\" St. Peter looks down his list, and says, \"Go to room 24, but be very quiet as you pass room 8.\" Another man arrives at the gates of heaven. \"Religion?\" \"Baptist.\" \"Go to room 18, but be very quiet as you pass room 8.\" A third man arrives at the gates. \"Religion?\" \"Jewish.\" \"Go to room 11, but be very quiet as you pass room 8.\" The man says, \"I can understand there being different rooms for different religions, but why must I be quiet when I pass room 8?\" St. Peter tells him, \"Well the Catholics are in room 8, and they think they're the only ones here." 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             j27 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              "Clinton returns from a vacation in Arkansas and walks down the steps of Air Force One with two pigs under his arms. At the bottom of the steps, he says to the honor guardsman, \"These are genuine Arkansas Razor-Back Hogs. I got this one for Chelsea and this one for Hillary.\" The guardsman replies, \"Nice trade, Sir.\"" 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             j53 
## "One Sunday morning William burst into the living room and said, \"Dad! Mom! I have some great news for you! I am getting married to the most beautiful girl in town. She lives a block away and her name is Susan.\" After dinner, William's dad took him aside. \"Son, I have to talk with you. Your mother and I have been married 30 years.. She's a wonderful wife but she has never offered much excitement in the bedroom, so I used to fool around with women a lot. Susan is actually your half-sister, and I'm afraid you can't marry her.\" William was heart-broken. After eight months he eventually started dating girls again. A year later he came home and very proudly announced, \"Dianne said yes! We're getting married in June.\" Again his father insisted on another private conversation and broke the sad news. \"Dianne is your half-sister too, William. I'm awfully sorry about this.\" William was furious! He finally decided to go to his mother with the news. \"Dad has done so much harm.. I guess I'm never going to get married,\" he complained. \"Every time I fall in love, Dad tells me the girl is my half-sister.\" His mother just shook her head. \"Don't pay any attention to what he says, dear. He's not really your father.\"" 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             j49 
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "Three engineering students were gathered together discussing the possible designers of the human body. One said, \"It was a mechanical engineer. Just look at all the joints.\" Another said, \"No, it was an electrical engineer. The nervous systems many thousands of electrical connections.\" The last said, \"Actually it was a civil engineer. Who else would run a toxic waste pipeline through a recreational area?\""
LS0tDQp0aXRsZTogIkRBVEEgNjEyIFByb2plY3QgNCINCmF1dGhvcjogIkpvaG4gSy4gSGFuY29jayINCmRhdGU6ICI2LzE5LzIwMjAiDQpvdXRwdXQ6DQogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IHBhcGVyDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiBubw0KLS0tDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShyZWNvbW1lbmRlcmxhYikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocmVzaGFwZTIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShjYVRvb2xzKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShybWRmb3JtYXRzKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmpzb24pDQpsaWJyYXJ5KGpzb25saXRlKQ0KYGBgDQoNCiMgUHJvamVjdCBTY29wZQ0KDQpUaGUgZ29hbCBvZiB0aGlzIGFzc2lnbm1lbnQgaXMgZ2l2ZSB5b3UgcHJhY3RpY2Ugd29ya2luZyB3aXRoIGFjY3VyYWN5IGFuZCBvdGhlciByZWNvbW1lbmRlciBzeXN0ZW0gbWV0cmljcy4gQ2hvb3NlIGEgZGlmZmVyZW50IGRhdGFzZXQgdG8gd29yayB3aXRoIGZyb20geW91ciBwcmV2aW91cyBwcm9qZWN0cy4NCg0KRGVsaXZlcmFibGVzDQoxLiBBcyBpbiB5b3VyIHByZXZpb3VzIGFzc2lnbm1lbnRzLCBjb21wYXJlIHRoZSBhY2N1cmFjeSBvZiBhdCBsZWFzdCB0d28gcmVjb21tZW5kZXIgc3lzdGVtIGFsZ29yaXRobXMgYWdhaW5zdCB5b3VyIG9mZmxpbmUgZGF0YS4NCjIuIEltcGxlbWVudCBzdXBwb3J0IGZvciBhdCBsZWFzdCBvbmUgYnVzaW5lc3Mgb3IgdXNlciBleHBlcmllbmNlIGdvYWwgc3VjaCBhcyBpbmNyZWFzZWQgc2VyZW5kaXBpdHksIG5vdmVsdHksIG9yIGRpdmVyc2l0eS4NCjMuIENvbXBhcmUgYW5kIHJlcG9ydCBvbiBhbnkgY2hhbmdlIGluIGFjY3VyYWN5IGJlZm9yZSBhbmQgYWZ0ZXIgeW91J3ZlIG1hZGUgdGhlIGNoYW5nZSBpbiAjMi4NCjQuIEFzIHBhcnQgb2YgeW91ciB0ZXh0dWFsIGNvbmNsdXNpb24sIGRpc2N1c3Mgb25lIG9yIG1vcmUgYWRkaXRpb25hbCBleHBlcmltZW50cyB0aGF0IGNvdWxkIGJlIHBlcmZvcm1lZCBhbmQvb3IgbWV0cmljcyB0aGF0IGNvdWxkIGJlIGV2YWx1YXRlZCBvbmx5IGlmIG9ubGluZSBldmFsdWF0aW9uIHdhcyBwb3NzaWJsZS4gQWxzbywgYnJpZWZseSBwcm9wb3NlIGhvdyB5b3Ugd291bGQgZGVzaWduIGEgcmVhc29uYWJsZSBvbmxpbmUgZXZhbHVhdGlvbiBlbnZpcm9ubWVudC4NCg0KIyBJbnRyb2R1Y3Rpb24NCg0KRm9yIHRoaXMgcHJvamVjdCwgSSBjaG9zZSBKZXN0ZXI1SyBkYXRhc2V0LiBUaGUgcHJvamVjdCB3aWxsDQoNCi0gRXhwbG9yZSB0aGUgSmVzdGVyNUsgZGF0YXNldA0KLSBDb21wYXJlIHRoZSBVQ0JGLCBQb3B1bGFyLCBSYW5kb20sIGFuZCBIeWJyaWQgcmVjb21tZW5kZXINCi0gRGlzY3VzcyBhIHJlYXNvbmFibGUgb25saW5lIGV2YWx1YXRpb24NCg0KDQojIyBEYXRhIEV4cGxvcmF0aW9uIC0gSmVzdGVyIDVLIGRhdGFzZXQNCiANClRoZSBKZXN0ZXIgNUsgZGF0YXNldCBpcyBhIGRhdGFzZXQgY29uc2lzdGluZyBvZiA1MDAwIHVzZXJzIHJhdGluZyAxMDAgb2Ygam9rZXMgd2hpY2ggbWVhbnMgYSBjb21iaW5hdGlvbiBvZiA1MDAsMDAwIHVzZXJzIGFuZCByYXRpbmdzLiANCg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpkYXRhKCJKZXN0ZXI1ayIpDQpKZXN0ZXI1aw0KDQpgYGANCg0KSmVzdGVyNUsgaGFzIGEgc2xvdCBmb3IgdGhlIGRhdGEuICBMb29raW5nIGF0IHRoaXMgc2xvdCwgd2Ugc2VlIHRoYXQgdGhlIGRhdGEgc2xvdCBvZiBKZXN0ZXI1SyBpcyBvZiB0aGUgY2xhc3MgZGdjTWF0cml4LiANCg0KYGBge3J9DQpzbG90TmFtZXMoSmVzdGVyNWspDQpgYGANCg0KYGBge3J9DQpjbGFzcyhKZXN0ZXI1a0BkYXRhKQ0KYGBgDQoNCiMjIyBUaGUgSm9rZXMNCg0KRWFjaCBjb2x1bW4gaW4gdGhlIGRhdGFzZXQgcmVwcmVzZW50cyBhIGpva2UgZm9yIGEgdG90YWwgb2YgMTAwIGpva2VzLiANCg0KYGBge3J9DQpsZW5ndGgoY29sbmFtZXMoSmVzdGVyNWtAZGF0YSkpDQpgYGANCg0KVGhlIGNvbHVtbnMgY29udGFpbiB0aGUgbmFtZXMgb2YgdGhlIGpva2VzLiBCZWxvdyBhcmUgdGhlIGZpcnN0IGZpdmUgY29sdW1uIG5hbWVzIGFuZCBiZWxvdyB0aGF0IGlzIHRoZSB0ZXh0IGZvciBlYWNoIG9mIHRoZXNlIGpva2VzLiANCg0KYGBge3J9DQpoZWFkKGNvbG5hbWVzKEplc3RlcjVrQGRhdGEpLDUpDQpgYGANCg0KYGBge3J9DQp0YWlsKEplc3Rlckpva2VzLDYpDQpgYGANCg0KIyMjIFRoZSB1c2VyIHJhdGluZ3MNCg0KVGhlIGRhdGFzZXQgY29udGFpbnMgYSB0b3RhayBvZiAzNjIsMTA2IHJhdGluZ3Mgd2hpY2ggbWVhbnMgdGhhdCB0aGUgZGF0YXNldCBpcyBkZW5zZSBhcHJyb3guIDcyJSBmdWxsLiANCg0KYGBge3J9DQpucmF0aW5ncyhKZXN0ZXI1aykNCmBgYA0KDQpUaGUgcmF0aW5ncyBvZiB0aGUgam9rZXMgcmFuZ2UgZnJvbSBhIC05Ljk1IHRvIGEgcG9zaXRpdmUgOS45IHdpdGggYW4gYXZlcmFnZSByYXRpbmcgb2YgMC44NTI1LiBUaGlzIHJlc3VsdCBpcyBhZnRlciByZW1vdmluZyBlbnRyaWVzIHdpdGhvdXQgYSAiMCIgcmF0aW5nLg0KDQpgYGB7cn0NCmpva2VzX3ZlY3Rvcl9yYXRpbmdzIDwtICBhcy52ZWN0b3IoSmVzdGVyNWtAZGF0YSkNCmpva2VzX3ZlY3Rvcl9yYXRpbmdzIDwtIGpva2VzX3ZlY3Rvcl9yYXRpbmdzW2pva2VzX3ZlY3Rvcl9yYXRpbmdzICE9IDAgXQ0KcmFuZ2Uoam9rZXNfdmVjdG9yX3JhdGluZ3MpDQpgYGANCg0KYGBge3J9DQpzdW1tYXJ5KGpva2VzX3ZlY3Rvcl9yYXRpbmdzKQ0KYGBgDQoNCmBgYHtyfQ0KaGlzdChqb2tlc192ZWN0b3JfcmF0aW5ncywgbWFpbj0iRGlzdHJpYnV0aW9uIG9mIHJhdGluZ3MiLCBjb2w9InllbGxvdyIpDQphYmxpbmUodj1tZWFuKGpva2VzX3ZlY3Rvcl9yYXRpbmdzKSxjb2w9InJlZCIpDQpgYGANCg0KRnJvbSB0aGlzIHZpc3VhbGl6YXRpb24sIHdlIHNlZSB0aGF0IGpva2VzIHJhdGVkIGZyb20gMyB0byA0IG9uIGEgc2NhbGUgb2YgLTEwIHRvIDEwLCB3ZXJlIHRoZSBtb3N0IGNvbW1vbmx5IHJhdGVkIGpva2UuIE92ZXJhbGwsIG1vcmUgam9rZXMgYXJlIHJhdGVkIHBvc2l0aXZlbHkgdGhhbiBuZWdhdGl2ZWx5LiANCg0KIyMgTW9zdCByYXRlZCBKb2tlcw0KDQpgYGB7cn0NCnJhdGluZ3NfcGVyX2pva2UgPC0gY29sQ291bnRzKEplc3RlcjVrKQ0Kam9rZV9mcmVxdWVuY3kgPC0gZGF0YS5mcmFtZShqb2tlcyA9IG5hbWVzKHJhdGluZ3NfcGVyX2pva2UpLCB0b2xkID0gcmF0aW5nc19wZXJfam9rZSkNCmpva2VfZnJlcXVlbmN5IDwtIGpva2VfZnJlcXVlbmN5ICU+JSANCiAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyh0b2xkKSkNCg0Kam9rZV9mcmVxdWVuY3lbMTozLF0NCg0KYGBgDQoNCmBgYHtyfQ0KSmVzdGVySm9rZXNbImo4Il0NCmBgYA0KDQpgYGB7cn0NCkplc3Rlckpva2VzWyJqMTMiXQ0KYGBgDQoNCmBgYHtyfQ0KSmVzdGVySm9rZXNbImoxNSJdDQpgYGANCg0KIyMgQmluYXJpemUgdnMuIE5vcm1hbGl6ZQ0KDQpUaGUgZ29hbCBvZiB0aGlzIHByb2plY3QgaXMgdG8gY29tcGFyZSByZWNvbW1lbmRlciBtb2RlbHMgYWNjb3VudGluZyBmb3IgZmluZGluZyBub3ZlbCBvciBzZXJlbmRpcGl0b3VzIHJlY29tbWVuZGF0aW9ucy4gSWYgSSBiaW5hcml6ZSB0aGUgZGF0YSwgdGhlbiBJIGxvc2UgdGhlIGdyYW51YWxhcml0eSBvZiB0aGUgcmVjb21tZW5kYXRpb24uICBBbGwgdGhhdCBJIHdvdWxkIGJlIGFibGUgdG8gdGVsbCB3b3VsZCBiZSB0aGF0IHRoZSB1c2VyIHJhdGVkIHRoZSBqb2tlLCBub3QgaG93IHdlbGwgb3IgaGlnaGx5IHJhdGVkLg0KDQpOb3JtYWxpemluZyB0aGUgZGF0YSBzZWVtcyB0byBiZSB0aGUgYmV0dGVyIGFwcHJvYWNoIGdpdmVuIHRoZSB3aWRlIHJhbmdlIG9mIHRoZSBkYXRhLiANCg0KRmlyc3QsIEkgZGVmaW5lZCBhIG1pbmltdW0gbnVtYmVyIG9mIDk5IHVzZXJzIHdobyBoYXZlIHJhdGVkIGF0IGxlYXN0IDI1IGpva2VzLiANCg0KDQpgYGB7cn0NCg0KSmVzdGVyX0pva2VzIDwtIEplc3RlcjVrW3Jvd0NvdW50cyhKZXN0ZXI1aykgPiA5OSwgY29sQ291bnRzKEplc3RlcjVrKSA+IDI1XQ0KSmVzdGVyX0pva2VzIA0KYGBgDQoNCg0KDQpgYGB7cn0NCmF2ZXJhZ2VfcmF0aW5nc19wZXJfdXNlciA8LSByb3dNZWFucyhKZXN0ZXJfSm9rZXMpDQpxcGxvdChhdmVyYWdlX3JhdGluZ3NfcGVyX3VzZXIpICsgc3RhdF9iaW4oYmlud2lkdGggPSAwLjEpICsNCmdndGl0bGUoIkRpc3RyaWJ1dGlvbiBvZiB0aGUgYXZlcmFnZSByYXRpbmcgcGVyIHVzZXIiKQ0KYGBgDQoNCg0KDQoNCg0KTm9ybWFsaXppbmcgdGhlIEpva2VzDQoNCmBgYHtyfQ0KSmVzdGVyX0pva2VzX25vcm0gPC0gbm9ybWFsaXplKEplc3Rlcl9Kb2tlcykNCnN1bShyb3dNZWFucyhKZXN0ZXJfSm9rZXNfbm9ybSApID4gMC4wMDAwMSkNCmBgYA0KDQpgYGB7cn0NCmpva2VzX3ZlY3Rvcl9yYXRpbmdzX25vcm0gPC0gIGFzLnZlY3RvcihKZXN0ZXJfSm9rZXNfbm9ybUBkYXRhKQ0Kam9rZXNfdmVjdG9yX3JhdGluZ3Nfbm9ybSAgPC0gam9rZXNfdmVjdG9yX3JhdGluZ3Nfbm9ybVtqb2tlc192ZWN0b3JfcmF0aW5nc19ub3JtICAhPSAwIF0NCg0KaGlzdChqb2tlc192ZWN0b3JfcmF0aW5nc19ub3JtLCBtYWluPSJEaXN0cmlidXRpb24gb2YgcmF0aW5ncyIsIGNvbD0ieWVsbG93IikNCmFibGluZSh2PW1lYW4oam9rZXNfdmVjdG9yX3JhdGluZ3Nfbm9ybSApLGNvbD0icmVkIikNCmBgYA0KDQoNCiMjIFVzZXIgU2ltaWxhcml0eQ0KDQoNCkluIHRoZSBibG9ja3MgYmVsb3csIEkgdXNlZCBSZWNvbW1lbmRlckxhYidzIHNpbWlsYXJpdHkgZnVuY3Rpb24gdG8gZmluZCBzaW1pbGFyaXR5IGFtb25nIHRoZSB0b3AgNTAgdXNlcnMuICBUaGUgbW9yZSByZWQgYmxvY2tzIGluZGljYXRlcyBzaW1pbGFyaXR5IGJldHdlZW4gdGhlIHVzZXJzLiBUaGlzIHNtYWxsIHNhbXBsZSB0ZWxscyB1cyB0aGF0IHRoZXJlIGlzIHNvbWUgc2ltaWxhcml0aWVzIGJldHdlZW4gdGhlIHVzZXJzIGJ1dCBub3QgdmVyeSBzdHJvbmcuIA0KDQoNCmBgYHtyfQ0Kc2ltaWxhcml0eV91c2VycyA8LSBzaW1pbGFyaXR5KEplc3Rlcl9Kb2tlc1sxOjUwLCBdLCBtZXRob2QgPSJjb3NpbmUiLCB3aGljaCA9ICJ1c2VycyIpDQoNCmBgYA0KDQpgYGB7cn0NCmltYWdlKGFzLm1hdHJpeChzaW1pbGFyaXR5X3VzZXJzKSwgbWFpbiA9ICJVc2VyIHNpbWlsYXJpdHkiKQ0KYGBgDQoNCiMjIFVzZXIgU2ltaWxhcml0eQ0KDQpDb252ZXJzZWx5LCB3ZSBzZWUgYSBzdHJvbmdlciBzaW1pbGFyaXR5IGJldHdlZW4gdGhlIGpva2VzIHRoZW1zZWx2ZXMuIA0KDQoNCmBgYHtyfQ0Kc2ltaWxhcml0eV9qb2tlcyA8LSBzaW1pbGFyaXR5KEplc3Rlcl9Kb2tlc1ssIDE6NTBdLCBtZXRob2QgPSJjb3NpbmUiLCB3aGljaCA9ICJpdGVtcyIpDQoNCmBgYA0KDQpgYGB7cn0NCmltYWdlKGFzLm1hdHJpeChzaW1pbGFyaXR5X2pva2VzKSwgbWFpbiA9ICJKb2tlIHNpbWlsYXJpdHkiKQ0KYGBgDQoNCg0KIyBDb21wYXJpbmcgQ29sbGFib3JhdGlvbiBGaWx0ZXJpbmcgTW9kZWxzIC0gVUJDRiBhbmQgSUJDRg0KDQpJbiB0aGlzIHNlY3Rpb24sIEkgYXBwbGllZCB0aGUgVUJDRiBhbmQgSUJDRiBhbGdvcml0aG1zIHRvIHRoZSBKZXN0ZXIgZGF0YXNldC4gIEZvciBTZXJlbmRpcGl0eSwgSSB0aGVuIGFwcGxpZWQgdGhlIFBPUFVMQVIgYWxnb3JpdGhtLiANCg0KIyMgSy1Gb2xkIFNwbGl0DQoNCg0KYGBge3J9DQpuX2ZvbGQgPC0gNg0KaXRlbXNfdG9fa2VlcCA8LSAxMA0KcmF0aW5nX3RocmVzaG9sZCA8LSAwDQpgYGANCg0KDQpgYGB7cn0NCmV2YWxfc2V0cyAgPC0gZXZhbHVhdGlvblNjaGVtZShkYXRhID0gSmVzdGVyX0pva2VzLCBtZXRob2QgPSAiY3Jvc3MtdmFsaWRhdGlvbiIsIGsgPSBuX2ZvbGQsIGdpdmVuID0gaXRlbXNfdG9fa2VlcCwgZ29vZFJhdGluZyA9IHJhdGluZ190aHJlc2hvbGQpDQoNCmBgYA0KDQoNCmBgYHtyfQ0Kc2l6ZV9zZXRzIDwtIHNhcHBseShldmFsX3NldHNAcnVuc1RyYWluLCBsZW5ndGgpDQpzaXplX3NldHMNCmBgYA0KDQoNCiMjIEV2YWx1YXRpb24gb2YgbW9kZWxzDQoNClRvIGV2YWx1YXRlIHRoZSB0d28gbW9kZWxzLCBJIGNyZWF0ZWQgYSBsaXN0IG9mIFVCQ0YgYW5kIFNWRCBtb2RlbHMgd2l0aCBkaWZmZXJlbnQgcGFyYW1ldGVycyAocGVhcnNvbiBhbmQgY29zaW5lKS4gVGhpcyBsaXN0IHdhcyBmZWQgaW50byB0aGUgZXZhbHVhdGUgZnVuY3Rpb24gYW5kIGJlbG93LiBUaGUgdmlzdWFsaXphdGlvbnMgYmVsb3cgYm90aCBzaG93IHRoYXQgdGhlIFVCQ0YgdXNpbmcgdGhlICJwZWFyc29uIiBtZXRob2QgaGFkIHRoZSBsYXJnZXIgYXJlYSB1bmRlciB0aGUgY3VydmUuIA0KDQpJbiBjb25jbHVzaW9uLCB0aGlzIHByb2plY3QgaGFzIHNob3duIHRoYXQgaWYgd2Ugd2FudCBvdXIgbW9kZWwgdG8gYmUgbW9yZSBwcmVjaXNlIHdpdGggaXRzIHJlY29tbWVuZGF0aW9ucywgd2Ugd291bGQgY2hvb3NlIHRoZSBVQkNGIG1vZGVsIGFuZCByZWNvbW1lbmQgZml2ZSBvciBsZXNzIG1vdmllcy4gSWYgdGhlIG51bWJlciBvZiByZWNvbW1lbmRhdGlvbnMgaXMgNTAgb3IgYWJvdmUsIHRoZW4gdGhlIFVCQ0YtcGVhcnNvbiBtb2RlbCBkb2VzIG5vdCBwZXJmb3JtIGJldHRlciB0aGFuIHRoZSBvdGhlciBtb2RlbHMuIA0KDQoNCmBgYHtyfQ0KbW9kZWxzX3RvX2V2YWx1YXRlIDwtIGxpc3QoDQpVQkNGX2NvcyA9IGxpc3QobmFtZSA9ICJVQkNGIiwgcGFyYW0gPSBsaXN0KG1ldGhvZCA9ImNvc2luZSIpKSwNClVCQ0ZfY29yID0gbGlzdChuYW1lID0gIlVCQ0YiLCBwYXJhbSA9IGxpc3QobWV0aG9kID0icGVhcnNvbiIpKSwNCklCQ0ZfY29zID0gbGlzdChuYW1lID0gIklCQ0YiLCBwYXJhbSA9IGxpc3QobWV0aG9kID0iY29zaW5lIikpLA0KSUJDRl9jb3IgPSBsaXN0KG5hbWUgPSAiSUJDRiIsIHBhcmFtID0gbGlzdChtZXRob2QgPSJwZWFyc29uIikpDQopDQoNCm5fcmVjb21tZW5kYXRpb25zIDwtIGMoMSwgNSwgc2VxKDEwLCAxMDAsIDEwKSkNCmBgYA0KDQoNCg0KYGBge3J9DQpjb21wYXJlX3Jlc3VsdHMgPC0gZXZhbHVhdGUoeCA9IGV2YWxfc2V0cywgbWV0aG9kID0gbW9kZWxzX3RvX2V2YWx1YXRlLCBuPSBuX3JlY29tbWVuZGF0aW9ucykNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdChjb21wYXJlX3Jlc3VsdHMsIGFubm90YXRlID0gNCwgbGVnZW5kID0gInRvcGxlZnQiKSArIHRpdGxlKCJST0MgY3VydmUiKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChjb21wYXJlX3Jlc3VsdHMsICJwcmVjL3JlYyIsIGFubm90YXRlID0gNSwgbGVnZW5kID0gImJvdHRvbXJpZ2h0IikNCnRpdGxlKCJQcmVjaXNpb24tcmVjYWxsIikNCmBgYA0KDQoNCiMjIyBTZXJlbmRpcGl0eQ0KDQpUbyBhY2NvdW50IGZvciBzZXJlbmRpcGl0eSwgSSBhZGRlZCBhbmQgZXZhbHVhdGVkIHRoZSBQT1BVTEFSIG1vZGVsIHdpdGhvdXQgYW55IHBhcmFtZXRlcnMuICBXZSBzZWUgdGhhdCB0aGlzIG1vZGVsIHBlcmZvcm1zIGFzIHdlbGwgYXMgdGhlIFVCQ0YgbW9kZWxzIGFuZCBvdXRwZXJmb3JtcyB0aGUgSUJDRiBtb2RlbC4gDQoNCg0KYGBge3J9DQpyZWNvbW1lbmRlcl9tb2RlbHMgPC0gcmVjb21tZW5kZXJSZWdpc3RyeSRnZXRfZW50cmllcyhkYXRhVHlwZSA9InJlYWxSYXRpbmdNYXRyaXgiKQ0KcmVjb21tZW5kZXJfbW9kZWxzJFBPUFVMQVJfcmVhbFJhdGluZ01hdHJpeCRwYXJhbWV0ZXJzDQpgYGANCg0KDQoNCmBgYHtyfQ0KbW9kZWxzX3RvX2V2YWx1YXRlIDwtIGxpc3QoDQpVQkNGX2NvcyA9IGxpc3QobmFtZSA9ICJVQkNGIiwgcGFyYW0gPSBsaXN0KG1ldGhvZCA9ImNvc2luZSIpKSwNClVCQ0ZfY29yID0gbGlzdChuYW1lID0gIlVCQ0YiLCBwYXJhbSA9IGxpc3QobWV0aG9kID0icGVhcnNvbiIpKSwNCklCQ0ZfY29zID0gbGlzdChuYW1lID0gIklCQ0YiLCBwYXJhbSA9IGxpc3QobWV0aG9kID0iY29zaW5lIikpLA0KSUJDRl9jb3IgPSBsaXN0KG5hbWUgPSAiSUJDRiIsIHBhcmFtID0gbGlzdChtZXRob2QgPSJwZWFyc29uIikpLA0KUE9QVUxBUj0gbGlzdChuYW1lID0gIlBPUFVMQVIiLCBwYXJhbT1OVUxMKQ0KKQ0KDQpuX3JlY29tbWVuZGF0aW9ucyA8LSBjKDEsIDUsIHNlcSgxMCwgMTAwLCAxMCkpDQpgYGANCg0KDQoNCmBgYHtyfQ0KY29tcGFyZV9yZXN1bHRzIDwtIGV2YWx1YXRlKHggPSBldmFsX3NldHMsIG1ldGhvZCA9IG1vZGVsc190b19ldmFsdWF0ZSwgbj0gbl9yZWNvbW1lbmRhdGlvbnMpDQpgYGANCg0KDQpgYGB7cn0NCnBsb3QoY29tcGFyZV9yZXN1bHRzLCBhbm5vdGF0ZSA9IDQsIGxlZ2VuZCA9ICJ0b3BsZWZ0IikgKyB0aXRsZSgiUk9DIGN1cnZlIikNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdChjb21wYXJlX3Jlc3VsdHMsICJwcmVjL3JlYyIsIGFubm90YXRlID0gNSwgbGVnZW5kID0gImJvdHRvbXJpZ2h0IikNCnRpdGxlKCJQcmVjaXNpb24tcmVjYWxsIikNCmBgYA0KDQoNCiMjIEJ1aWxkaW5nIHRoZSBGaW5hbCBNb2RlbCAtIFBPUFVMQVIgdnMuIFJBTkRPTQ0KDQpJbiB0aGlzIGZpbmFsIHNlY3Rpb24sIEkgY29tcGFyZSB0aGUgUE9QVUxBUiBtb2RlbCB0byBhIFJBTkRPTSBtb2RlbC4gVGhlIFBPUFVMQVIgbW9kZWwgcmVjb21tZW5kcyBqb2tlcyB0aGF0IGFyZSB0aGUgbW9zdCBwb3B1bGFyIHRvIHVzZXJzIHdobyBoYXZlIG5vdCByYXRlZCB0aGUgam9rZXMuIFRoZSBSQU5ET00gbW9kZWwgYXNzaWducyByYXRpbmdzIG9uIGEgcmFuZG9tIGJhc2lzLiANCg0KDQpCZWxvdywgSSBleHRyYWN0ZWQgYSBzYW1wbGUgb2YgMTUwMCB1c2VycyBmcm9tIHRoZSBKZXN0ZXI1ayBkYXRhc2V0IGFuZCBleHRyYWN0IHRoZSByYXRpbmdfam9rZXNfbWF0cml4IGZyb20gdGhlIG9iamVjdC4gDQoNCiMjIyBTYW1wbGUgdGhlIERhdGENCg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpqZXN0ZXJfZGF0YSA8LSBzYW1wbGUoSmVzdGVyNWssMTUwMCkNCnJhdGluZ19qb2tlc19tYXRyaXggPC0gZ2V0UmF0aW5nTWF0cml4KGplc3Rlcl9kYXRhKQ0Kc3RyKHJhdGluZ19qb2tlc19tYXRyaXgpDQpgYGANCg0KIyMjIE5vcm1hbGl6ZSB0aGUgRGF0YQ0KDQpgYGB7cn0NCmplc3Rlcl9kYXRhX25vcm0gPC0gbm9ybWFsaXplKGplc3Rlcl9kYXRhLCBtZXRob2Q9Inotc2NvcmUiKQ0KcGFyKG1mcm93PWMoMiwxKSkNCnBsb3QoZGVuc2l0eShnZXRSYXRpbmdzKGplc3Rlcl9kYXRhKSksIG1haW49Ik9yaWdpbmFsIikNCnBsb3QoZGVuc2l0eShnZXRSYXRpbmdzKGplc3Rlcl9kYXRhX25vcm0pKSwgbWFpbj0iTm9ybWFsaXplZCIpDQpgYGANCg0KIyMjIFRyYWluLCBUZXN0LCBTcGxpdA0KDQpCZWxvdyB1c2luZyB0aGUgZXZhbHVhdGlvbiBzY2hlbWUgbWV0aG9kLCA4MCUgb2YgdGhlIGRhdGEgaXMgYWxsb2NhdGVkIHRvIHRyYWluaW5nLiAgVGhlIG1vZGVsIHdpbGwgdGFrZSAyMCBqb2tlcyBmcm9tIGVhY2ggdXNlciBhbmQgcHV0IHRoZW0gYXNpZGUuIE9uY2UgdGhlIG1vZGVsIGlzIGJ1aWx0LCBwcmVkaWN0aW9ucyB3aWxsIGJlIG1hZGUgb24gdGhlc2UgMjAgam9rZXMgYW5kIHRob3NlIHByZWRpY3Rpb25zIHdpbGwgYmUgZXZhbHVhdGVkIGFnYWluc3QgdGhlIGFjdHVhbCByYXRpbmdzLiANCg0KDQpgYGB7cn0NCnBsYW4gPC0gZXZhbHVhdGlvblNjaGVtZShqZXN0ZXJfZGF0YV9ub3JtLCBtZXRob2Q9InNwbGl0IiwgdHJhaW49MC44LCBnaXZlbj0xMCwgZ29vZFJhdGluZz0yKQ0KcGxhbg0KYGBgDQoNClRoZSBnZXREYXRhIGZ1bmN0aW9uIGV4dHJhY3RzIHRoZSB0cmFpbiwgdGVzdCwgYW5kIHRlc3Rfa25vd24gc2V0cyBmcm9tIHRoZSBwbGFuLiAgVGhlIHRlc3Qgc2V0IG9yICJrbm93biIgZXh0cmFjdHMga25vd24gcmF0aW5ncyBmcm9tIHRoZSB0ZXN0IHNldC4gDQoNCg0KYGBge3J9DQp0cmFpbiA8LSBnZXREYXRhKHBsYW4sIHR5cGU9InRyYWluIikNCnRyYWluDQpgYGANCg0KDQpgYGB7cn0NCnRlc3QgPC0gZ2V0RGF0YShwbGFuLCB0eXBlPSJ1bmtub3duIikNCnRlc3QNCmBgYA0KDQoNCmBgYHtyfQ0KdGVzdF9rbm93biA8LSBnZXREYXRhKHBsYW4sICJrbm93biIpDQp0ZXN0X2tub3duDQpgYGANCg0KIyMjIFRyYWluIGFuZCBUZXN0IHRoZSBSYW5kb20gTW9kZWwNCg0KSW4gdGhlIGJsb2NrcyBiZWxvdywgSSBidWlsdCBSYW5kb20gbW9kZWwgd2hpY2ggcmFkb21seSBwcnJlZGljdHMgdGhlIHJhdGluZ3MuICBJdCB3aWxsIGJlIHVzZWQgYXMgcmVmZXJlbmNlIG1vZGVsIGZvciB0aGUgUE9QVUxBUiBtb2RlbC4gDQoNCmBgYHtyfQ0KcmFuZG9tX21vZGVsIDwtIFJlY29tbWVuZGVyKHRyYWluLCAiUkFORE9NIikNCnJhbmRvbV9tb2RlbA0KYGBgDQoNCmBgYHtyfQ0KZ2V0TW9kZWwocmFuZG9tX21vZGVsKQ0KYGBgDQoNCg0KDQpUaGlzIGlzIGEgcmFuZG9tIG1vZGVsIHRoYXQgcHJvZHVjZXMgYSByYW5kb20gbnVtYmVyIGJldHdlZW4gLTYuMDk1IGFuZCA2LjY0Nw0KDQoNCmBgYHtyfQ0KcmFuZG9tX3ByZWRpY3QgPC0gcHJlZGljdChyYW5kb21fbW9kZWwsIHRlc3Rfa25vd24sIG49NSwgdHlwZT0idG9wTkxpc3QiKQ0KcmFuZG9tX3ByZWRpY3RAaXRlbXNbMV0NCmBgYA0KDQpUaGUgcHJlZGljdCBmdW5jdGlvbiBwcmVkaWN0cyB0aGUgdG9wIDUgam9rZXMgdGhhdCB0aGUgdXNlciB3b3VsZCBoYXZlIHJhdGVkLiBIZXJlLCB3ZSBzZWUgdGhhdCBqb2tlcyA5MiwgOTcsIDcyLCAxNSwgYW5kIDI5IGFyZSByZWNvbW1lbmRlZCBmb3IgdXNlciAxLiANCg0KDQojIyBQT1BVTEFSIG1vZGVsDQoNCg0KYGBge3J9DQpwb3B1bGFyX21vZGVsIDwtIFJlY29tbWVuZGVyKHRyYWluLCAiUE9QVUxBUiIpDQpwb3B1bGFyX21vZGVsDQpgYGANCg0KYGBge3J9DQpwb3B1bGFyX3ByZWRpY3QgPC0gcHJlZGljdChwb3B1bGFyX21vZGVsLCB0ZXN0X2tub3duLCBuID0gNSwgdHlwZSA9InRvcE5MaXN0IikNCnBvcHVsYXJfcHJlZGljdEBpdGVtc1sxXQ0KYGBgDQoNCmBgYHtyfQ0KcG9wdWxhcl9wcmVkaWN0QHJhdGluZ3NbMV0NCmBgYA0KDQoNCmBgYHtyfQ0KbmV3X21vZGVsc190b19ldmFsdWF0ZSA8LSBsaXN0KA0KUkFORE9NPWxpc3QobmFtZT0iUkFORE9NIiwgcGFyYW09TlVMTCksDQpQT1BVTEFSPSBsaXN0KG5hbWUgPSAiUE9QVUxBUiIsIHBhcmFtPU5VTEwpDQopDQoNCm5fcmVjb21tZW5kYXRpb25zIDwtIGMoMSwgNSwgc2VxKDEwLCAxMDAsIDEwKSkNCmBgYA0KDQoNCg0KYGBge3J9DQoNCnBsYW5fMiA8LSBldmFsdWF0aW9uU2NoZW1lKGplc3Rlcl9kYXRhLCBtZXRob2Q9ImNyb3NzIiwgdHJhaW49MC45LCBnaXZlbiA9IDEwLGdvb2RSYXRpbmc9NSkNCnJlc3VsdHMgPC0gZXZhbHVhdGUocGxhbl8yLCBtZXRob2QgPSBuZXdfbW9kZWxzX3RvX2V2YWx1YXRlLCB0eXBlID0gInRvcE5MaXN0IiwgbiA9bl9yZWNvbW1lbmRhdGlvbnMgKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChyZXN1bHRzLCBhbm5vdGF0ZSA9IDQsIGxlZ2VuZCA9ICJ0b3BsZWZ0IikgKyB0aXRsZSgiUk9DIGN1cnZlIikNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdChyZXN1bHRzLCAicHJlYy9yZWMiLCBhbm5vdGF0ZSA9IDUsIGxlZ2VuZCA9ICJib3R0b21yaWdodCIpDQp0aXRsZSgiUHJlY2lzaW9uLXJlY2FsbCIpDQpgYGANCg0KDQpgYGB7cn0NCmF2ZyhyZXN1bHRzKQ0KYGBgDQoNCiMjIyBSTVNFDQoNCmBgYHtyfQ0KUk1TRV9SYW5kb20gPC0gZXZhbHVhdGUocGxhbiwgbWV0aG9kPSJSQU5ET00iLCB0eXBlPSJyYXRpbmdzIikNCmF2ZyhSTVNFX1JhbmRvbSkNCmBgYA0KDQpgYGB7cn0NClJNU0VfUE9QVUxBUiA8LSBldmFsdWF0ZShwbGFuLCBtZXRob2Q9IlBPUFVMQVIiLCB0eXBlPSJyYXRpbmdzIikNCmF2ZyhSTVNFX1BPUFVMQVIpDQpgYGANCg0KIyBDb25jbHVzaW9uDQoNCg0KT24gdGhlIGJhc2lzIG9mIEFPQywgUHJlY2lzaW9uL1JlY2FsbCwgYW5kIHRoZSBSTVNFLCB0aGUgUE9QVUxBUiBtb2RlbCBvdXRwZXJmb3JtcyB0aGUgUkFORE9NIG1vZGVsLiBJT1csIHBvcHVsYXJzIGpva2VzIGFyZSByYXRlZCBoaWdoZXIgYnkgdXNlcnMgdGhhbiBhIHJhbmRvbSBzZWxlY3Rpb24gb2Ygam9rZXMuIEFub3RoZXIgZXhwZXJpbWVudCB0aGF0IGNvdWxkIGJlIHJ1biB3b3VsZCBiZSBBL0IgdGVzdGluZy4gRm9yIGV4YW1wbGUsIGxldHMgc2F5IHRoYXQgeW91IGhhdmUgYW4gb25saW5lIHN0cmVhbWluZyBtdXNpYyBzZXJ2aWNlLiBUaGlzIHNlcnZpY2Ugd291bGQgZGVwbG95IHR3byByZWNvbW1lbmRlciBtb2RlbHMgYW5kIGJhc2VkIG9uIHdoZXRoZXIgdGhlIHVzZXJzIGFjdHVhbGx5IHNlbGVjdCB0aGUgc29uZ3MgYW5kIHJhdGUgdGhlbSB3b3VsZCBnaXZlIHlvdSB0aGUgYmVzdCBldmFsdWF0aW9uLiANCg0KDQpUbyBjb25jbHVkZSwgbGV0J3MgbG9vayBhdCBhIGZldyBvZiB0aGUgam9rZXMgdGhlIFBPUFVMQVIgbW9kZWwgcmVjb21tZW5kZWQuIA0KDQoNCmBgYHtyfQ0KdG9wX2pva2VzIDwtIGMocG9wdWxhcl9wcmVkaWN0QGl0ZW1zW1sxXV0pDQpmb3IgKGkgaW4gMTpsZW5ndGgodG9wX2pva2VzKSl7DQogICAgdG9wX2pva2VzW2ldID0gKHBhc3RlMCgiaiIsdG9wX2pva2VzW2ldKSkNCg0KfQ0KSmVzdGVySm9rZXNbdG9wX2pva2VzXQ0KYGBgDQo=