March 16, 2017

0. Introduction

The advent of R notebooks in October 2016 allow us to analyze data in the popular notebook format, similarly to iPython. Using R notebooks, we can not only embed R code, but also Python and SQL code as well.

1. Loading the data

The Lahman database compiles baseball statistics from the 1870’s until the present. I downloaded the 2016 version and set up a MySQL server using XAMPP. After you install it, fire up the XAMPP Control Panel and start the Apache and MySQL modules.


The Lahman database is ~65 MB, so I had to change some of the settings in the php.ini file to allow for larger files to be uploaded to the server. To make the changes, click on the Config button on the Apache module row and select php.ini

The RMySQL R package allows us to query a MySQL database by creating something called a connection to the database.

Herein we load the RMySQL package, connect to the database, and list the tables in it:

library(RMySQL)
drv <- dbDriver("MySQL")
db <- dbConnect(drv, user="root", dbname = "lahman2016", host="127.0.0.1")
dbListTables(db)
 [1] "allstarfull"         "appearances"         "awardsmanagers"      "awardsplayers"      
 [5] "awardssharemanagers" "awardsshareplayers"  "batting"             "battingpost"        
 [9] "collegeplaying"      "fielding"            "fieldingof"          "fieldingofsplit"    
[13] "fieldingpost"        "halloffame"          "homegames"           "managers"           
[17] "managershalf"        "master"              "parks"               "pitching"           
[21] "pitchingpost"        "salaries"            "schools"             "seriespost"         
[25] "teams"               "teamsfranchises"     "teamshalf"          

The Lahman database has 4 main tables. The MASTER table contains players’ natural information like date and city of birth as well as physical characteristics, such as height and weight. The Batting, Pitching, and Fielding tables carry players’ statistics relevant to those skills.

2. Raw SQL queries: The 1980 Major League Baseball season

2.1 1981 Topps baseball cards

On my childhood Saturdays in Puerto Rico, my father would go to a bakery store and buy hot “criollo” bread for everyone, and a couple of Topps baseball packs for me. The packs cost somewhere in the vicinity of 10 or 15 cents and they included a stick of gum, too. Gee whiz!

A general strike notwithstanding, baseball was a big deal in 1981, and the baseball world at the time was buzzing with Fernandomania, the spectacular rise to prominence of a Los Angeles Dodgers pitcher from Sonora named Fernando “El Toro” Valenzuela. That year, Valenzuela would go on to win both the Rookie of the Year and Cy Young awards in the National League, and beat the mighty Yankees in the World Series in front of 56,000 faithful at Dodger Stadium. In our neck of the woods, we also paid a lot of attention to the exploits of one José “Cheo” Cruz, Puerto Rico’s most distinguished baseball player in the early eighties.

The 1981 Topps cards had all the players’ statistics up to 1980, so I was pretty well acquainted with MLB’s top performers in 1980. Let’s query the Lahman database on player’s performances in 1980.

2.2 1980 home run and batting average leaders

The 1980 home run leaders can be found by querying the Batting table and specifying the year with a WHERE clause. We can also sort the results with ORDER BY and limit the number of results returned by the query with LIMIT. SELECT lets us specify which columns of the resulting table to return.

SELECT yearID, playerID, teamID, hr
FROM Batting
WHERE yearID = 1980
ORDER BY HR DESC
LIMIT 10

Note that the results returned are for the whole MLB, and are not segmented by league like we are used to. Also, the Batting table only has the player and team codes, rather than their names.

We can also perform a very similar query, this time making use of a formula, to obtain the top ten batting averages in 1980. We filter the results to only include players with at least 400 AB’s

SELECT yearID AS year, playerID, teamID, H AS Hits, AB AS At_Bats, (H/AB) AS Batting_Average
FROM Batting
WHERE yearID = 1980 AND AB > 400
ORDER BY Batting_Average DESC
LIMIT 10

2.3 Using JOINs

2.3.1 Home runs and batting average

To obtain the player names in the home run example, we have to cross-reference the playerID’s of the resulting table with the MASTER table using a JOIN statement. The JOIN statement performs an inner join between the Batting and MASTER tables ON playerID to find the player’s name. Here we do it for home runs:

SELECT yearID, CONCAT(nameFirst, " ", nameLast) AS fullName, teamID, hr
FROM Batting
JOIN MASTER
ON Batting.playerID = MASTER.playerID
WHERE yearID = 1980
ORDER BY HR DESC
LIMIT 10

In addition, to find the teams’ names, JOIN the table we just got with the Teams table, ON the teamID field. We will take the last query in its entirety, alias its resulting table as “hrtop10”, and JOIN it with Teams ON teamID.

SELECT hrtop10.yearID, hrtop10.fullName, Teams.name as teamName, hrtop10.hr
FROM (SELECT yearID, CONCAT(nameFirst, " ", nameLast) AS fullName, teamID, hr
      FROM Batting
      JOIN MASTER
      ON Batting.playerID = MASTER.playerID
      WHERE yearID = 1980
      ORDER BY HR DESC
      LIMIT 10) hrtop10 /*table alias*/
JOIN Teams 
ON hrtop10.teamID = Teams.teamID AND hrtop10.yearID = Teams.yearID
WHERE hrtop10.yearID = 1980
ORDER BY hrtop10.hr DESC

There we go! Some memorable names in that list! Mike Schmidt, the Hall of Fame third baseman considered one of the best ever to play that position in history. Indeed, he was named MVP of the National League in 1980. His 48 HR’s that year stood as a record for a third baseman until 2007. His Philadelphia Phillies would go on to win the World Series in 1980, and he was named MVP of the Series, too. Bob Horner, another third baseman slugger, who in 1986 became the 11th player ever to hit four home runs in a single game. Schmidt is a member of that club, too. Of course, who can forget Mr. October, who in the sixth game of the 1977 World Series hit 3 home runs with 3 swings.

We can do it for the 1980 batting average leaders table as well:

SELECT batop10.yearID AS year, batop10.fullName, Teams.name as teamName, batop10.H AS Hits, batop10.AB AS At_Bats, batop10.Batting_Average
FROM (SELECT yearID, CONCAT(nameFirst, " ", nameLast) AS fullName, teamID, H, AB, (H/AB) AS Batting_Average
      FROM Batting
      JOIN MASTER
      ON Batting.playerID = MASTER.playerID
      WHERE yearID = 1980 AND AB > 400
      ORDER BY Batting_Average DESC
      LIMIT 10) batop10 /*table alias*/
JOIN Teams 
ON batop10.teamID = Teams.teamID AND batop10.yearID = Teams.yearID
WHERE batop10.yearID = 1980
ORDER BY batop10.Batting_Average DESC

1980 also saw George Brett, with a 0.390 batting average, come close to joining the 0.400 fraternity, one that hasn’t welcomed any new members since 1941. Since 1941, only Tony Gwynn has come closer than Brett to the 0.400 mark. I also have an indelible memory of George Brett furiously storming the field during the pine tar incident of 1983. His Kansas City Royals reached the World Series in 1980, where they lost to the Phillies.

2.3.2 Hall of Fame inductees

Another query we can answer using a join: Which players active in 1980 went on to join Cooperstown’s Hall of Fame? Since pitchers and batters are kept in separate tables, let’s do the batters first. We can do a JOIN between a table of batters active in 1980 and a table of fielders whose position was not pitcher. We use the DISTINCT function for this second table because some players played more than one position in 1980 and they would therefore be reported more than once if we don’t use DISTINCT. For example, Carlton Fisk played first base, third base, outfielder, and catcher in 1980.

SELECT batter1980.playerID
FROM  (SELECT playerID FROM Batting WHERE yearID = 1980) batter1980
JOIN (SELECT DISTINCT(playerID) FROM Fielding WHERE yearID = 1980 AND Pos <> "P") notPitcher1980
ON batter1980.playerID = notPitcher1980.playerID

Then we can take that table, alias it as batterNotPitcher1980 and JOIN it to the HallOfFame table, filtered to include inductees only, ON playerID. Additionally, before performing the JOIN, we can compute the percentage of voters received by the inductees from the sportswriters the year they were inducted. The threshold for induction is 75% of the votes.

SELECT batterNotPitcher1980.playerID, hof.Percentage_of_votes_received, hof.yearInducted
FROM (SELECT batter1980.playerID
      FROM  (SELECT playerID FROM Batting WHERE yearID = 1980) batter1980
      JOIN (SELECT DISTINCT(playerID) FROM Fielding WHERE yearID = 1980 AND Pos <> "P") notPitcher1980
      ON batter1980.playerID = notPitcher1980.playerID) batterNotPitcher1980
JOIN (SELECT 100.0*(votes/ballots) AS Percentage_of_votes_received, playerID, yearID AS yearInducted FROM HallOfFame WHERE inducted = "Y") hof
ON hof.playerID = batterNotPitcher1980.playerID
ORDER BY hof.Percentage_of_votes_received DESC

Then we can JOIN the table we just got with the MASTER table to find the players’ names, using the playerID like we did before. We are using DISTINCT because if a player played for more than one team in 1980, he will appear twice in the MASTER table, and in our results, which we don’t want. On the pitchers side, Gaylord Perry played for two different teams in 1980.

SELECT DISTINCT(CONCAT(nameFirst, " ", nameLast)) AS fullName, hof1980Batting.Percentage_of_votes_received, hof1980Batting.yearInducted
FROM (SELECT batterNotPitcher1980.playerID, hof.Percentage_of_votes_received, hof.yearInducted
      FROM (SELECT batter1980.playerID
            FROM  (SELECT playerID FROM Batting WHERE yearID = 1980) batter1980
            JOIN (SELECT DISTINCT(playerID) FROM Fielding WHERE yearID = 1980 AND Pos <> "P") notPitcher1980
            ON batter1980.playerID = notPitcher1980.playerID) batterNotPitcher1980
      JOIN (SELECT 100.0*(votes/ballots) AS Percentage_of_votes_received, playerID, yearID AS yearInducted FROM HallOfFame WHERE inducted = "Y") hof
      ON hof.playerID = batterNotPitcher1980.playerID
      ORDER BY hof.Percentage_of_votes_received DESC) hof1980Batting
JOIN MASTER
ON hof1980Batting.playerID = MASTER.playerID
ORDER BY hof1980Batting.Percentage_of_votes_received DESC

Tim Raines! He was not elected until 2017, his last year of eligibility. Some have suggested that his induction may have been partly due to a more sophisticated understanding of sabermetrics. Good for him! Rickey Henderson! No one is prouder of Rickey than Rickey, the greatest, of all time! I remember a catcher could really make a name for himself if he caught Rickey stealing. Rickey stole 100 bases in 1980, and 130 in 1982. I also remember the gracefulness of Ozzie Smith, the Wizard of Oz.

Now we do it for the pitchers, in a single step:

SELECT DISTINCT(CONCAT(nameFirst, " ", nameLast)) AS fullName, hof1980Pitching.Percentage_of_votes_received, hof1980Pitching.yearInducted
FROM (SELECT pitcherNotBatter1980.playerID, hof.Percentage_of_votes_received, hof.yearInducted
      FROM (SELECT pitcher1980.playerID
            FROM  (SELECT playerID FROM Pitching WHERE yearID = 1980) pitcher1980
            JOIN (SELECT DISTINCT(playerID) FROM Fielding WHERE yearID = 1980 AND Pos = "P") onlyPitcher1980
            ON pitcher1980.playerID = onlyPitcher1980.playerID) pitcherNotBatter1980
      JOIN (SELECT 100.0*(votes/ballots) AS Percentage_of_votes_received, playerID, yearID AS yearInducted FROM HallOfFame WHERE inducted = "Y") hof
      ON hof.playerID = pitcherNotBatter1980.playerID
      ORDER BY hof.Percentage_of_votes_received DESC) hof1980Pitching
JOIN MASTER
ON hof1980Pitching.playerID = MASTER.playerID
ORDER BY hof1980Pitching.Percentage_of_votes_received DESC

Tom Seaver held the record for the highest voting percentage received from the sportswriters to enter the Hall of Fame until Ken Griffey Jr. broke it in 2016. Nolan Ryan, who has at least three records that probably will never be topped: 5,714 career strikeouts, 7 career no-hitters, and 383 strikeouts in a single season, ranks third in percentage of votes received to Cooperstown, behind Seaver and Griffey. Steve Carlton won 2 games in the 1980 World Series playing for the Phillies, a Series they won. His 304 innings pitched in 1980 were the last time anyone pitched 300 or more. He led the NL in wins (24), innings, and strikeouts (286) that year, and won the NL Cy Young award as well.

2.4 Using GROUP BY

2.4.1 Top home run hitters by position in 1980

Suppose we want to know the top home run hitters by position in 1980, e.g., which first baseman hit more home runs than any other? We will do it by steps, as we built the earlier queries. We will first create a table by joining the Batting and Fielding tables for 1980

SELECT hr1980.playerID, hr1980.hr, pos1980.Pos
FROM (SELECT playerID, hr FROM Batting WHERE yearID = 1980) hr1980
JOIN (SELECT playerID, Pos FROM Fielding WHERE yearID = 1980 ) pos1980
ON hr1980.playerID = pos1980.playerID

Then we create a table that outputs the maximum home runs by position, using GROUP BY.

SELECT MAX(hr1980.hr) as max_hr, pos1980.Pos
FROM (SELECT playerID, hr FROM Batting WHERE yearID = 1980) hr1980
JOIN (SELECT playerID, Pos FROM Fielding WHERE yearID = 1980 ) pos1980
ON hr1980.playerID = pos1980.playerID
GROUP BY pos1980.Pos

There are seven fielding positions, so we just have the highest home run totals at each position. Then we take the two manufactured tables and JOIN them on two fields: player position and home runs. The first table will match the second only where home runs are highest, at each position.

SELECT playerID, posTable.hr as home_runs, posTable.Pos as Position
FROM (SELECT hr1980.playerID, hr1980.hr, pos1980.Pos
      FROM (SELECT playerID, hr FROM Batting WHERE yearID = 1980) hr1980
      JOIN (SELECT playerID, Pos FROM Fielding WHERE yearID = 1980 ) pos1980
      ON hr1980.playerID = pos1980.playerID) posTable
JOIN (SELECT MAX(hr1980.hr) as max_hr, pos1980.Pos
      FROM (SELECT playerID, hr FROM Batting WHERE yearID = 1980) hr1980
      JOIN (SELECT playerID, Pos FROM Fielding WHERE yearID = 1980 ) pos1980
      ON hr1980.playerID = pos1980.playerID
      GROUP BY pos1980.Pos) posTableMax
ON posTable.Pos = posTableMax.Pos AND posTable.hr = posTableMax.max_hr

Finally, we do the JOIN with the MASTER table to get the players’ names:

SELECT DISTINCT(CONCAT(nameFirst, " ", nameLast)) AS fullName, home_runs, Position
FROM (SELECT playerID, posTable.hr as home_runs, posTable.Pos as Position
      FROM (SELECT hr1980.playerID, hr1980.hr, pos1980.Pos
            FROM (SELECT playerID, hr FROM Batting WHERE yearID = 1980) hr1980
            JOIN (SELECT playerID, Pos FROM Fielding WHERE yearID = 1980 ) pos1980
            ON hr1980.playerID = pos1980.playerID) posTable
      JOIN (SELECT MAX(hr1980.hr) as max_hr, pos1980.Pos
            FROM (SELECT playerID, hr FROM Batting WHERE yearID = 1980) hr1980
            JOIN (SELECT playerID, Pos FROM Fielding WHERE yearID = 1980 ) pos1980
            ON hr1980.playerID = pos1980.playerID
            GROUP BY pos1980.Pos) posTableMax
      ON posTable.Pos = posTableMax.Pos AND posTable.hr = posTableMax.max_hr) maxHrByPosition
JOIN MASTER
ON MASTER.playerID = maxHrByPosition.playerID
ORDER BY maxHrByPosition.home_runs DESC

Great! There was a tie at the outfielder position between Ben Oglivie and Reggie Jackson. We see beloved Hall of Famers Gary Carter at catcher and Robin Yount at shortstop. Carter was a key player of the New York Mets in 1986, when they won the World Series. Yount played his entire career with the Milwaukee Bucks. In 1982, he was named MVP of the American League after receiving 27 out of 28 first-place votes from the writers.

2.4.2 Home run leaders of the eighties

We can find out the home run leaders by year throughout the eighties using the same GROUP BY construct. Start by finding the maximum number of home runs hit by year for each year of the decade.

SELECT MAX(hrEighties.hr) as max_hr, yearID
FROM (SELECT yearID, playerID, hr FROM Batting WHERE yearID > 1979 AND yearID < 1990) hrEighties
GROUP BY yearID

Then create a table of home runs of every player that batted in the eighties.

SELECT yearID, playerID, teamID, hr FROM Batting WHERE yearID > 1979 AND yearID < 1990

Now JOIN the two tables ON home runs and year. We get more than 10 results because of the ties. In 1982, for example, Reggie Jackson and Gorman Thomas were tied for the lead with 39 home runs each.

SELECT hrEightiesTable.yearID as year, playerID, teamID, hrEightiesTable.hr
FROM (SELECT yearID, playerID, teamID, hr FROM Batting WHERE yearID > 1979 AND yearID < 1990) hrEightiesTable
JOIN (SELECT MAX(hrEighties.hr) as max_hr, yearID
      FROM (SELECT yearID, playerID, hr FROM Batting WHERE yearID > 1979 AND yearID < 1990) hrEighties
      GROUP BY yearID) hrEightiesTableMax
ON hrEightiesTable.yearID = hrEightiesTableMax.yearID AND hrEightiesTable.hr = hrEightiesTableMax.max_hr

What about categorizing them by leagues? We can do it by three small modifications to the previous query. First, for each of the inner SELECT, we return the lgID column, i.e., AL or NL. Second, in the table where we do the grouping, we group by league, then by year: GROUP BY lgID, yearID. Third, on the JOIN, we join the two tables by league in addition to home runs and year.

SELECT hrEightiesTable.lgID as league, hrEightiesTable.yearID as year, playerID, teamID, hrEightiesTable.hr
FROM (SELECT lgID, yearID, playerID, teamID, hr FROM Batting WHERE yearID > 1979 AND yearID < 1990) hrEightiesTable
JOIN (SELECT MAX(hrEighties.hr) as max_hr, lgID, yearID
      FROM (SELECT lgID, yearID, playerID, hr FROM Batting WHERE yearID > 1979 AND yearID < 1990) hrEighties
      GROUP BY lgID, yearID) hrEightiesTableMax
ON hrEightiesTable.lgID = hrEightiesTableMax.lgID AND hrEightiesTable.yearID = hrEightiesTableMax.yearID AND hrEightiesTable.hr = hrEightiesTableMax.max_hr
ORDER BY hrEightiesTable.yearID, hrEightiesTable.lgID


3.0 Importing data from the Lahman SQL database into R

We can import data into R to do visualizations. We do this by designing and manufacturing a table in SQL first, then importing it as a data frame into R.

3.1 Home runs by batting preference

I want to plot the distribution of home runs in 1980 by batting preference, left or right. We first build the query to manufacture the table the way we want it, then we import the table as a dataframe into R. We create a table by filtering the Batting table to include only 1980 data, then JOIN it with the MASTER table ON playerID to get the batting preference for that player. It’s pretty straightforward, but we still we need to GROUP BY the Batting table results by home run totals, per player, to account for players that played for more than one team in 1980. For example, Jason Thompson played for two teams in 1980, the Detroit Tigers and the California Angels:

SELECT playerID, teamID, hr, G
FROM Batting WHERE yearID=1980 AND playerID = "thompja01"


So he should count as one left-handed -per the MASTER table- batter with 21 home runs in 1980.

Here is the whole query. We are filtering for players who participated in at least 100 games. This is because home runs were rare enough in 1980, even for players that participated in every game. If we include players that were used sparingly, we would get a lot of zero’s.

SELECT b1980.hr_sum AS hr, MASTER.bats
FROM (SELECT playerID, sum(hr) as hr_sum
      FROM Batting
      WHERE yearID = 1980 AND G > 99
      GROUP BY playerID) b1980
JOIN MASTER
ON b1980.playerID = MASTER.playerID


We use the function dbGetQuery() to get bring the manufactured table as a dataframe into R:

batPref1980 <- dbGetQuery(db,"SELECT b1980.hr_sum AS hr, MASTER.bats
                              FROM (SELECT playerID, sum(hr) as hr_sum
                                    FROM Batting
                                    WHERE yearID = 1980 AND G > 99
                                    GROUP BY playerID) b1980
                              JOIN MASTER
                              ON b1980.playerID = MASTER.playerID")
Warning messages:
1: In .local(conn, statement, ...) :
  Decimal MySQL column 5 imported as numeric
2: In .local(conn, statement, ...) :
  Decimal MySQL column 5 imported as numeric
3: In .local(conn, statement, ...) :
  Decimal MySQL column 1 imported as numeric
4: In .local(conn, statement, ...) :
  Decimal MySQL column 1 imported as numeric
5: In .local(conn, statement, ...) :
  Decimal MySQL column 1 imported as numeric
6: In .local(conn, statement, ...) :
  Decimal MySQL column 0 imported as numeric
batPref1980$bats <- as.factor(batPref1980$bats)
summary(batPref1980)
       hr        bats   
 Min.   : 0.00   B: 32  
 1st Qu.: 3.00   L: 85  
 Median : 8.00   R:124  
 Mean   :10.09          
 3rd Qu.:15.00          
 Max.   :48.00          


Then we can plot the home run distributions by batting preference. We will use the rBokeh library, which renders plots with pan and zoom capabilities.

library(rbokeh)
figure(title = "Home runs hit vs batting preference in 1980", width = 600, xlab = "Batting preference", ylab = "Home runs") %>%  ly_boxplot(x=bats, y=hr, data = batPref1980, fill_color = "#56B4E9", line_color = "black", fill_alpha=1, width = 0.4)


Whoa, 32 ambidextrous batters who saw a lot of action in 1980! One of them hit more than 30 home runs, when 30 home runs was still considered newsworthy. Who was that?

SELECT CONCAT(nameFirst, " ", nameLast) AS fullName, bats
FROM (SELECT playerID FROM Batting WHERE yearID = 1980 AND hr > 30) studs1980
JOIN MASTER ON MASTER.playerID = studs1980.playerID
WHERE MASTER.bats = "B"

It was future Hall of Famer Eddie Murray!

3.2 Team attendance by league and division

We want to visualize ballpark attendance in 1980. In the Lahman database, the attendance is kept in the Teams table. A simple query returns the info we want.

SELECT name AS team, attendance, lgID as league, divID AS division FROM Teams WHERE yearID = 1980


Now we can embed that query into dbGetQuery() to bring the results into R.

attendance_1980 <- dbGetQuery(db, "SELECT name AS team, attendance, lgID as league, divID AS division 
                          FROM Teams WHERE yearID = 1980")
# Changing attendance, which is read as a string, to numeric 
attendance_1980$attendance <- as.numeric(attendance_1980$attendance)
# Changing the "E" and "W" in division to "East" and "West"
attendance_1980$division[attendance_1980$division == "E"] <- "East"
attendance_1980$division[attendance_1980$division == "W"] <- "West"
# Creating a "league_division" column
attendance_1980$league_division <- paste(attendance_1980$league, attendance_1980$division)
summary(attendance_1980)
     team             attendance         league            division         league_division   
 Length:26          Min.   : 769206   Length:26          Length:26          Length:26         
 Class :character   1st Qu.:1152288   Class :character   Class :character   Class :character  
 Mode  :character   Median :1523542   Mode  :character   Mode  :character   Mode  :character  
                    Mean   :1654390                                                           
                    3rd Qu.:2161744                                                           
                    Max.   :3249287                                                           


Then we can create the boxplot.

figure(width=600, title = "Ballpark attendance in 1980", xlab = "League division", ylab = "Ballpark attendance") %>% ly_boxplot(x = league_division, y = attendance, data = attendance_1980, fill_color = "#56B4E9", line_color = "black", fill_alpha=1, width = 0.4) %>% y_axis(number_formatter = "numeral")


We can also visualize the attendance using a tree map.

library(treemap)
treemap(attendance_1980, index=c("league_division", "team"), vSize = "attendance", palette = c("#E69F00", "#56B4E9", "#009E73", "#CC79A7"), title = "Ballpark attendance by league division", title.legend = "League division", position.legend = "bottom")


Among other things, the plot shows the Los Angeles Dodgers had just about as much attendance as three other teams in the NL West combined: the San Diego Padres, the Atlanta Braves, and the San Francisco Giants. Although the Dodgers were the only MLB team to top 3 million fans in attendance that year, they finished the season second in the NL West, one game behind the Houston Astros.


References:

  1. Andres, Andy. Sabermetrics 101: Introduction to Baseball Analytics, Summer 2014. edX

  2. Beaulieu, Alan. Learning SQL. Sebastopol: O’Reilly Media, 2009. PDF

  3. Adler, Joseph. R in a Nutshell, Second Edition. Sebastopol: O’Reilly Media, 2012. PDF.

  4. Ericton and John Woo. How to select product that have the maximum price of each category? Retrieved from http://stackoverflow.com/questions/12366390/how-to-select-product-that-have-the-maximum-price-of-each-category

  5. Dirk Edderbuettel and David James. [R] connecting [logging] RMySQL to an external server - SOLVED Retrieved from https://stat.ethz.ch/pipermail/r-help/2007-December/148840.html

  6. The Trading Card Database. 1981 Topps cards. Retrieved from http://www.tradingcarddb.com/ViewSet.cfm/sid/85/1981-Topps.

LS0tDQp0aXRsZTogIkFuYWx5emluZyBiYXNlYmFsbCBzdGF0aXN0aWNzIHdpdGggU1FMIGFuZCBSIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCiMjIyMgTWFyY2ggMTYsIDIwMTcNCg0KIyMgMC4gSW50cm9kdWN0aW9uDQpUaGUgYWR2ZW50IG9mIFtSIG5vdGVib29rc10oaHR0cHM6Ly9ibG9nLnJzdHVkaW8ub3JnLzIwMTYvMTAvMDUvci1ub3RlYm9va3MvKSBpbiBPY3RvYmVyIDIwMTYgYWxsb3cgdXMgdG8gYW5hbHl6ZSBkYXRhIGluIHRoZSBwb3B1bGFyIG5vdGVib29rIGZvcm1hdCwgc2ltaWxhcmx5IHRvIGlQeXRob24uIFVzaW5nIFIgbm90ZWJvb2tzLCB3ZSBjYW4gbm90IG9ubHkgZW1iZWQgUiBjb2RlLCBidXQgYWxzbyBQeXRob24gYW5kIFNRTCBjb2RlIGFzIHdlbGwuDQoNCiMjIDEuIExvYWRpbmcgdGhlIGRhdGENCg0KVGhlIFtMYWhtYW4gZGF0YWJhc2VdKGh0dHA6Ly93d3cuc2VhbmxhaG1hbi5jb20vYmFzZWJhbGwtYXJjaGl2ZS9zdGF0aXN0aWNzLykgY29tcGlsZXMgYmFzZWJhbGwgc3RhdGlzdGljcyBmcm9tIHRoZSAxODcwJ3MgdW50aWwgdGhlIHByZXNlbnQuIEkgZG93bmxvYWRlZCB0aGUgMjAxNiB2ZXJzaW9uIGFuZCBzZXQgdXAgYSBNeVNRTCBzZXJ2ZXIgdXNpbmcgW1hBTVBQXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9YQU1QUCkuIEFmdGVyIHlvdSBpbnN0YWxsIGl0LCBmaXJlIHVwIHRoZSBYQU1QUCBDb250cm9sIFBhbmVsIGFuZCBzdGFydCB0aGUgQXBhY2hlIGFuZCBNeVNRTCBtb2R1bGVzLg0KDQohW10oWEFNUFBfQ29udHJvbF9QYW5lbC5QTkcgIlhBTVBQIENvbnRyb2wgUGFuZWwiKQ0KPGJyPg0KDQpUaGUgTGFobWFuIGRhdGFiYXNlIGlzIH42NSBNQiwgc28gSSBoYWQgdG8gY2hhbmdlIHNvbWUgb2YgdGhlIHNldHRpbmdzIGluIHRoZSBwaHAuaW5pIGZpbGUgdG8gYWxsb3cgZm9yIGxhcmdlciBmaWxlcyB0byBiZSB1cGxvYWRlZCB0byB0aGUgc2VydmVyLiBUbyBtYWtlIHRoZSBjaGFuZ2VzLCBjbGljayBvbiB0aGUgQ29uZmlnIGJ1dHRvbiBvbiB0aGUgQXBhY2hlIG1vZHVsZSByb3cgYW5kIHNlbGVjdCBwaHAuaW5pDQoNClRoZSBbUk15U1FMXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvUk15U1FML1JNeVNRTC5wZGYpIFIgcGFja2FnZSBhbGxvd3MgdXMgdG8gcXVlcnkgYSBNeVNRTCBkYXRhYmFzZSBieSBjcmVhdGluZyBzb21ldGhpbmcgY2FsbGVkIGEgY29ubmVjdGlvbiB0byB0aGUgZGF0YWJhc2UuDQoNCkhlcmVpbiB3ZSBsb2FkIHRoZSBSTXlTUUwgcGFja2FnZSwgY29ubmVjdCB0byB0aGUgZGF0YWJhc2UsIGFuZCBsaXN0IHRoZSB0YWJsZXMgaW4gaXQ6DQoNCmBgYHtyLCBlY2hvPVRSVUV9DQpsaWJyYXJ5KFJNeVNRTCkNCmRydiA8LSBkYkRyaXZlcigiTXlTUUwiKQ0KZGIgPC0gZGJDb25uZWN0KGRydiwgdXNlcj0icm9vdCIsIGRibmFtZSA9ICJsYWhtYW4yMDE2IiwgaG9zdD0iMTI3LjAuMC4xIikNCmRiTGlzdFRhYmxlcyhkYikNCmBgYA0KDQpUaGUgTGFobWFuIGRhdGFiYXNlIGhhcyA0IG1haW4gdGFibGVzLiBUaGUgTUFTVEVSIHRhYmxlIGNvbnRhaW5zIHBsYXllcnMnIG5hdHVyYWwgaW5mb3JtYXRpb24gbGlrZSBkYXRlIGFuZCBjaXR5IG9mIGJpcnRoIGFzIHdlbGwgYXMgcGh5c2ljYWwgY2hhcmFjdGVyaXN0aWNzLCBzdWNoIGFzIGhlaWdodCBhbmQgd2VpZ2h0LiBUaGUgQmF0dGluZywgUGl0Y2hpbmcsIGFuZCBGaWVsZGluZyB0YWJsZXMgY2FycnkgcGxheWVycycgc3RhdGlzdGljcyByZWxldmFudCB0byB0aG9zZSBza2lsbHMuDQoNCiMjIDIuIFJhdyBTUUwgcXVlcmllczogVGhlIDE5ODAgTWFqb3IgTGVhZ3VlIEJhc2ViYWxsIHNlYXNvbg0KIyMjIDIuMSAxOTgxIFRvcHBzIGJhc2ViYWxsIGNhcmRzDQpPbiBteSBjaGlsZGhvb2QgU2F0dXJkYXlzIGluIFB1ZXJ0byBSaWNvLCBteSBmYXRoZXIgd291bGQgZ28gdG8gYSBiYWtlcnkgc3RvcmUgYW5kIGJ1eSBob3QgImNyaW9sbG8iIGJyZWFkIGZvciBldmVyeW9uZSwgYW5kIGEgY291cGxlIG9mIFtUb3Bwc10oaHR0cHM6Ly93d3cudG9wcHMuY29tLykgYmFzZWJhbGwgcGFja3MgZm9yIG1lLiBUaGUgcGFja3MgY29zdCBzb21ld2hlcmUgaW4gdGhlIHZpY2luaXR5IG9mIDEwIG9yIDE1IGNlbnRzIGFuZCB0aGV5IGluY2x1ZGVkIGEgc3RpY2sgb2YgZ3VtLCB0b28uIEdlZSB3aGl6IQ0KDQoNCiFbXShUb3Bwc19iYXNlYmFsbF9jYXJkc19wYWNrXzE5ODEuSlBHICJUb3BwcyBwYWNrIikNCg0KQSBbZ2VuZXJhbCBzdHJpa2VdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpLzE5ODFfTWFqb3JfTGVhZ3VlX0Jhc2ViYWxsX3N0cmlrZSkgbm90d2l0aHN0YW5kaW5nLCBiYXNlYmFsbCB3YXMgYSAqKmJpZyoqIGRlYWwgaW4gMTk4MSwgYW5kIHRoZSBiYXNlYmFsbCB3b3JsZCBhdCB0aGUgdGltZSB3YXMgYnV6emluZyB3aXRoIFtGZXJuYW5kb21hbmlhXShodHRwOi8vc2Fici5vcmcvcmVzZWFyY2gvZmVybmFuZG9tYW5pYSksIHRoZSBzcGVjdGFjdWxhciByaXNlIHRvIHByb21pbmVuY2Ugb2YgYSBbTG9zIEFuZ2VsZXMgRG9kZ2Vyc10oaHR0cDovL2xvc2FuZ2VsZXMuZG9kZ2Vycy5tbGIuY29tLykgcGl0Y2hlciBmcm9tIFNvbm9yYSBuYW1lZCBbRmVybmFuZG8gIkVsIFRvcm8iIFZhbGVuenVlbGFdKGh0dHA6Ly9tLm1sYi5jb20vcGxheWVyLzEyMzYxOS9mZXJuYW5kby12YWxlbnp1ZWxhKS4gVGhhdCB5ZWFyLCBWYWxlbnp1ZWxhIHdvdWxkIGdvIG9uIHRvIHdpbiBib3RoIHRoZSBSb29raWUgb2YgdGhlIFllYXIgYW5kIEN5IFlvdW5nIGF3YXJkcyBpbiB0aGUgTmF0aW9uYWwgTGVhZ3VlLCBhbmQgW2JlYXQgdGhlIG1pZ2h0eSBZYW5rZWVzIGluIHRoZSBXb3JsZCBTZXJpZXMgaW4gZnJvbnQgb2YgNTYsMDAwIGZhaXRoZnVsIGF0IERvZGdlciBTdGFkaXVtXShodHRwOi8vd3d3LmVzcG4uY29tL2xvcy1hbmdlbGVzL21sYi9jb2x1bW5zL3N0b3J5P2lkPTUzMjU0MzYpLiBJbiBvdXIgbmVjayBvZiB0aGUgd29vZHMsIHdlIGFsc28gcGFpZCBhIGxvdCBvZiBhdHRlbnRpb24gdG8gdGhlIGV4cGxvaXRzIG9mIG9uZSBbSm9zw6kgIkNoZW8iIENydXpdKGh0dHA6Ly93d3cuYXN0cm9zZGFpbHkuY29tL2ZpbGVzL3RlYW0vY3J1ei9jcnV6Lmh0bWwpLCBQdWVydG8gUmljbydzIG1vc3QgZGlzdGluZ3Vpc2hlZCBiYXNlYmFsbCBwbGF5ZXIgaW4gdGhlIGVhcmx5IGVpZ2h0aWVzLg0KDQoNCiFbXShWYWxlbnp1ZWxhX2Jhc2ViYWxsX2NhcmQuSlBHICJGZXJuYW5kbyAiRWwgVG9ybyIgVmFsZW56dWVsYSIpIVtdKENoZW9fQ3J1el9iYXNlYmFsbF9jYXJkLkpQRyAiSm9zw6kgIkNoZW8iIENydXoiKQ0KDQpUaGUgMTk4MSBUb3BwcyBjYXJkcyBoYWQgYWxsIHRoZSBwbGF5ZXJzJyBzdGF0aXN0aWNzIHVwIHRvIDE5ODAsIHNvIEkgd2FzIHByZXR0eSB3ZWxsIGFjcXVhaW50ZWQgd2l0aCBNTEIncyB0b3AgcGVyZm9ybWVycyBpbiAxOTgwLiBMZXQncyBxdWVyeSB0aGUgTGFobWFuIGRhdGFiYXNlIG9uIHBsYXllcidzIHBlcmZvcm1hbmNlcyBpbiAxOTgwLg0KDQojIyMgMi4yIDE5ODAgaG9tZSBydW4gYW5kIGJhdHRpbmcgYXZlcmFnZSBsZWFkZXJzDQpUaGUgMTk4MCBob21lIHJ1biBsZWFkZXJzIGNhbiBiZSBmb3VuZCBieSBxdWVyeWluZyB0aGUgQmF0dGluZyB0YWJsZSBhbmQgc3BlY2lmeWluZyB0aGUgeWVhciB3aXRoIGEgYFdIRVJFYCBjbGF1c2UuIFdlIGNhbiBhbHNvIHNvcnQgdGhlIHJlc3VsdHMgd2l0aCBgT1JERVIgQllgIGFuZCBsaW1pdCB0aGUgbnVtYmVyIG9mIHJlc3VsdHMgcmV0dXJuZWQgYnkgdGhlIHF1ZXJ5IHdpdGggYExJTUlUYC4gYFNFTEVDVGAgbGV0cyB1cyBzcGVjaWZ5IHdoaWNoIGNvbHVtbnMgb2YgdGhlIHJlc3VsdGluZyB0YWJsZSB0byByZXR1cm4uDQpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KU0VMRUNUIHllYXJJRCwgcGxheWVySUQsIHRlYW1JRCwgaHINCkZST00gQmF0dGluZw0KV0hFUkUgeWVhcklEID0gMTk4MA0KT1JERVIgQlkgSFIgREVTQw0KTElNSVQgMTANCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJ9DQpTRUxFQ1QgeWVhcklELCBwbGF5ZXJJRCwgdGVhbUlELCBocg0KRlJPTSBCYXR0aW5nDQpXSEVSRSB5ZWFySUQgPSAxOTgwDQpPUkRFUiBCWSBIUiBERVNDDQpMSU1JVCAxMA0KYGBgDQoNCk5vdGUgdGhhdCB0aGUgcmVzdWx0cyByZXR1cm5lZCBhcmUgZm9yIHRoZSB3aG9sZSBNTEIsIGFuZCBhcmUgbm90IHNlZ21lbnRlZCBieSBsZWFndWUgbGlrZSB3ZSBhcmUgdXNlZCB0by4gQWxzbywgdGhlIEJhdHRpbmcgdGFibGUgb25seSBoYXMgdGhlIHBsYXllciBhbmQgdGVhbSBjb2RlcywgcmF0aGVyIHRoYW4gdGhlaXIgbmFtZXMuIA0KDQpXZSBjYW4gYWxzbyBwZXJmb3JtIGEgdmVyeSBzaW1pbGFyIHF1ZXJ5LCB0aGlzIHRpbWUgbWFraW5nIHVzZSBvZiBhIGZvcm11bGEsIHRvIG9idGFpbiB0aGUgdG9wIHRlbiBiYXR0aW5nIGF2ZXJhZ2VzIGluIDE5ODAuIFdlIGZpbHRlciB0aGUgcmVzdWx0cyB0byBvbmx5IGluY2x1ZGUgcGxheWVycyB3aXRoIGF0IGxlYXN0IDQwMCBBQidzDQpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KU0VMRUNUIHllYXJJRCBBUyB5ZWFyLCBwbGF5ZXJJRCwgdGVhbUlELCBIIEFTIEhpdHMsIEFCIEFTIEF0X0JhdHMsIChIL0FCKSBBUyBCYXR0aW5nX0F2ZXJhZ2UNCkZST00gQmF0dGluZw0KV0hFUkUgeWVhcklEID0gMTk4MCBBTkQgQUIgPiA0MDANCk9SREVSIEJZIEJhdHRpbmdfQXZlcmFnZSBERVNDDQpMSU1JVCAxMA0KYGBgDQoNCmBgYHtzcWwgY29ubmVjdGlvbj1kYn0NClNFTEVDVCB5ZWFySUQgQVMgeWVhciwgcGxheWVySUQsIHRlYW1JRCwgSCBBUyBIaXRzLCBBQiBBUyBBdF9CYXRzLCAoSC9BQikgQVMgQmF0dGluZ19BdmVyYWdlDQpGUk9NIEJhdHRpbmcNCldIRVJFIHllYXJJRCA9IDE5ODAgQU5EIEFCID4gNDAwDQpPUkRFUiBCWSBCYXR0aW5nX0F2ZXJhZ2UgREVTQw0KTElNSVQgMTANCmBgYA0KDQoNCiMjIyAyLjMgVXNpbmcgYEpPSU5gcw0KIyMjIyAyLjMuMSBIb21lIHJ1bnMgYW5kIGJhdHRpbmcgYXZlcmFnZQ0KVG8gb2J0YWluIHRoZSBwbGF5ZXIgbmFtZXMgaW4gdGhlIGhvbWUgcnVuIGV4YW1wbGUsIHdlIGhhdmUgdG8gY3Jvc3MtcmVmZXJlbmNlIHRoZSBwbGF5ZXJJRCdzIG9mIHRoZSByZXN1bHRpbmcgdGFibGUgd2l0aCB0aGUgTUFTVEVSIHRhYmxlIHVzaW5nIGEgYEpPSU5gIHN0YXRlbWVudC4gVGhlIGBKT0lOYCBzdGF0ZW1lbnQgcGVyZm9ybXMgYW4gW2lubmVyIGpvaW5dKGh0dHBzOi8vd3d3Lnczc2Nob29scy5jb20vc3FsL3NxbF9qb2luX2lubmVyLmFzcCkgYmV0d2VlbiB0aGUgQmF0dGluZyBhbmQgTUFTVEVSIHRhYmxlcyBgT05gIHBsYXllcklEIHRvIGZpbmQgdGhlIHBsYXllcidzIG5hbWUuIEhlcmUgd2UgZG8gaXQgZm9yIGhvbWUgcnVuczoNCmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQpTRUxFQ1QgeWVhcklELCBDT05DQVQobmFtZUZpcnN0LCAiICIsIG5hbWVMYXN0KSBBUyBmdWxsTmFtZSwgdGVhbUlELCBocg0KRlJPTSBCYXR0aW5nDQpKT0lOIE1BU1RFUg0KT04gQmF0dGluZy5wbGF5ZXJJRCA9IE1BU1RFUi5wbGF5ZXJJRA0KV0hFUkUgeWVhcklEID0gMTk4MA0KT1JERVIgQlkgSFIgREVTQw0KTElNSVQgMTANCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJ9DQpTRUxFQ1QgeWVhcklELCBDT05DQVQobmFtZUZpcnN0LCAiICIsIG5hbWVMYXN0KSBBUyBmdWxsTmFtZSwgdGVhbUlELCBocg0KRlJPTSBCYXR0aW5nDQpKT0lOIE1BU1RFUg0KT04gQmF0dGluZy5wbGF5ZXJJRCA9IE1BU1RFUi5wbGF5ZXJJRA0KV0hFUkUgeWVhcklEID0gMTk4MA0KT1JERVIgQlkgSFIgREVTQw0KTElNSVQgMTANCmBgYA0KDQpJbiBhZGRpdGlvbiwgdG8gZmluZCB0aGUgdGVhbXMnIG5hbWVzLCBgSk9JTmAgdGhlIHRhYmxlIHdlIGp1c3QgZ290IHdpdGggdGhlIFRlYW1zIHRhYmxlLCBgT05gIHRoZSB0ZWFtSUQgZmllbGQuIFdlIHdpbGwgdGFrZSB0aGUgbGFzdCBxdWVyeSBpbiBpdHMgZW50aXJldHksIGFsaWFzIGl0cyByZXN1bHRpbmcgdGFibGUgYXMgImhydG9wMTAiLCBhbmQgYEpPSU5gIGl0IHdpdGggVGVhbXMgYE9OYCB0ZWFtSUQuDQpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KU0VMRUNUIGhydG9wMTAueWVhcklELCBocnRvcDEwLmZ1bGxOYW1lLCBUZWFtcy5uYW1lIGFzIHRlYW1OYW1lLCBocnRvcDEwLmhyDQpGUk9NIChTRUxFQ1QgeWVhcklELCBDT05DQVQobmFtZUZpcnN0LCAiICIsIG5hbWVMYXN0KSBBUyBmdWxsTmFtZSwgdGVhbUlELCBocg0KICAgICAgRlJPTSBCYXR0aW5nDQogICAgICBKT0lOIE1BU1RFUg0KICAgICAgT04gQmF0dGluZy5wbGF5ZXJJRCA9IE1BU1RFUi5wbGF5ZXJJRA0KICAgICAgV0hFUkUgeWVhcklEID0gMTk4MA0KICAgICAgT1JERVIgQlkgSFIgREVTQw0KICAgICAgTElNSVQgMTApIGhydG9wMTAgLyp0YWJsZSBhbGlhcyovDQpKT0lOIFRlYW1zIA0KT04gaHJ0b3AxMC50ZWFtSUQgPSBUZWFtcy50ZWFtSUQgQU5EIGhydG9wMTAueWVhcklEID0gVGVhbXMueWVhcklEDQpXSEVSRSBocnRvcDEwLnllYXJJRCA9IDE5ODANCk9SREVSIEJZIGhydG9wMTAuaHIgREVTQw0KYGBgDQoNCmBgYHtzcWwgY29ubmVjdGlvbj1kYn0NClNFTEVDVCBocnRvcDEwLnllYXJJRCwgaHJ0b3AxMC5mdWxsTmFtZSwgVGVhbXMubmFtZSBhcyB0ZWFtTmFtZSwgaHJ0b3AxMC5ocg0KRlJPTSAoU0VMRUNUIHllYXJJRCwgQ09OQ0FUKG5hbWVGaXJzdCwgIiAiLCBuYW1lTGFzdCkgQVMgZnVsbE5hbWUsIHRlYW1JRCwgaHINCiAgICAgIEZST00gQmF0dGluZw0KICAgICAgSk9JTiBNQVNURVINCiAgICAgIE9OIEJhdHRpbmcucGxheWVySUQgPSBNQVNURVIucGxheWVySUQNCiAgICAgIFdIRVJFIHllYXJJRCA9IDE5ODANCiAgICAgIE9SREVSIEJZIEhSIERFU0MNCiAgICAgIExJTUlUIDEwKSBocnRvcDEwIC8qdGFibGUgYWxpYXMqLw0KSk9JTiBUZWFtcyANCk9OIGhydG9wMTAudGVhbUlEID0gVGVhbXMudGVhbUlEIEFORCBocnRvcDEwLnllYXJJRCA9IFRlYW1zLnllYXJJRA0KV0hFUkUgaHJ0b3AxMC55ZWFySUQgPSAxOTgwDQpPUkRFUiBCWSBocnRvcDEwLmhyIERFU0MNCmBgYA0KDQpUaGVyZSB3ZSBnbyEgU29tZSBtZW1vcmFibGUgbmFtZXMgaW4gdGhhdCBsaXN0ISBbTWlrZSBTY2htaWR0XShodHRwOi8vYmFzZWJhbGxoYWxsLm9yZy9ob2Yvc2NobWlkdC1taWtlKSwgdGhlIEhhbGwgb2YgRmFtZSB0aGlyZCBiYXNlbWFuIGNvbnNpZGVyZWQgb25lIG9mIHRoZSBiZXN0IGV2ZXIgdG8gcGxheSB0aGF0IHBvc2l0aW9uIGluIGhpc3RvcnkuIEluZGVlZCwgaGUgd2FzIG5hbWVkIE1WUCBvZiB0aGUgTmF0aW9uYWwgTGVhZ3VlIGluIDE5ODAuIEhpcyA0OCBIUidzIHRoYXQgeWVhciBzdG9vZCBhcyBhIHJlY29yZCBmb3IgYSB0aGlyZCBiYXNlbWFuIHVudGlsIDIwMDcuIEhpcyBQaGlsYWRlbHBoaWEgUGhpbGxpZXMgd291bGQgZ28gb24gdG8gd2luIHRoZSBXb3JsZCBTZXJpZXMgaW4gMTk4MCwgYW5kIGhlIHdhcyBuYW1lZCBNVlAgb2YgdGhlIFNlcmllcywgdG9vLiBCb2IgSG9ybmVyLCBhbm90aGVyIHRoaXJkIGJhc2VtYW4gc2x1Z2dlciwgd2hvIGluIDE5ODYgW2JlY2FtZSB0aGUgMTF0aCBwbGF5ZXIgZXZlciB0byBoaXQgZm91ciBob21lIHJ1bnMgaW4gYSBzaW5nbGUgZ2FtZV0oaHR0cDovL3NhYnIub3JnL2xhdGVzdC9mb3N0ZXItMzAteWVhcnMtYWdvLWJvYi1ob3JuZXItaGl0LWZvdXItaG9tZS1ydW5zLWFuZC1icmF2ZXMtc3RpbGwtbG9zdCkuIFNjaG1pZHQgaXMgYSBtZW1iZXIgb2YgdGhhdCBbY2x1Yl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9NYWpvcl9MZWFndWVfQmFzZWJhbGxfc2luZ2xlLWdhbWVfaG9tZV9ydW5fbGVhZGVycyksIHRvby4gT2YgY291cnNlLCB3aG8gY2FuIGZvcmdldCBbTXIuIE9jdG9iZXJdKGh0dHA6Ly9iYXNlYmFsbGhhbGwub3JnL2hvZi9qYWNrc29uLXJlZ2dpZSksIHdobyBbaW4gdGhlIHNpeHRoIGdhbWUgb2YgdGhlIDE5NzcgV29ybGQgU2VyaWVzIGhpdCAzIGhvbWUgcnVucyB3aXRoIDMgc3dpbmdzXShodHRwOi8vd3d3Lmhpc3RvcnkuY29tL3RoaXMtZGF5LWluLWhpc3RvcnkvbXItb2N0b2Jlci1oaXRzLXRocmVlLWhvbWVycy1pbi10aHJlZS1zd2luZ3MpLg0KDQohW10oTWlrZV9TY2htaWR0X2Jhc2ViYWxsX2NhcmQuSlBHICJNaWtlIFNjaG1pZHQiKSFbXShCb2JfSG9ybmVyX2Jhc2ViYWxsX2NhcmQuSlBHICJCb2IgSG9ybmVyIikhW10oUmVnZ2llX0phY2tzb25fYmFzZWJhbGxfY2FyZC5KUEcgIk1yLiBPY3RvYmVyIikNCg0KDQpXZSBjYW4gZG8gaXQgZm9yIHRoZSAxOTgwIGJhdHRpbmcgYXZlcmFnZSBsZWFkZXJzIHRhYmxlIGFzIHdlbGw6DQpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KU0VMRUNUIGJhdG9wMTAueWVhcklEIEFTIHllYXIsIGJhdG9wMTAuZnVsbE5hbWUsIFRlYW1zLm5hbWUgYXMgdGVhbU5hbWUsIGJhdG9wMTAuSCBBUyBIaXRzLCBiYXRvcDEwLkFCIEFTIEF0X0JhdHMsIGJhdG9wMTAuQmF0dGluZ19BdmVyYWdlDQpGUk9NIChTRUxFQ1QgeWVhcklELCBDT05DQVQobmFtZUZpcnN0LCAiICIsIG5hbWVMYXN0KSBBUyBmdWxsTmFtZSwgdGVhbUlELCBILCBBQiwgKEgvQUIpIEFTIEJhdHRpbmdfQXZlcmFnZQ0KICAgICAgRlJPTSBCYXR0aW5nDQogICAgICBKT0lOIE1BU1RFUg0KICAgICAgT04gQmF0dGluZy5wbGF5ZXJJRCA9IE1BU1RFUi5wbGF5ZXJJRA0KICAgICAgV0hFUkUgeWVhcklEID0gMTk4MCBBTkQgQUIgPiA0MDANCiAgICAgIE9SREVSIEJZIEJhdHRpbmdfQXZlcmFnZSBERVNDDQogICAgICBMSU1JVCAxMCkgYmF0b3AxMCAvKnRhYmxlIGFsaWFzKi8NCkpPSU4gVGVhbXMgDQpPTiBiYXRvcDEwLnRlYW1JRCA9IFRlYW1zLnRlYW1JRCBBTkQgYmF0b3AxMC55ZWFySUQgPSBUZWFtcy55ZWFySUQNCldIRVJFIGJhdG9wMTAueWVhcklEID0gMTk4MA0KT1JERVIgQlkgYmF0b3AxMC5CYXR0aW5nX0F2ZXJhZ2UgREVTQw0KYGBgDQoNCmBgYHtzcWwgY29ubmVjdGlvbj1kYn0NClNFTEVDVCBiYXRvcDEwLnllYXJJRCBBUyB5ZWFyLCBiYXRvcDEwLmZ1bGxOYW1lLCBUZWFtcy5uYW1lIGFzIHRlYW1OYW1lLCBiYXRvcDEwLkggQVMgSGl0cywgYmF0b3AxMC5BQiBBUyBBdF9CYXRzLCBiYXRvcDEwLkJhdHRpbmdfQXZlcmFnZQ0KRlJPTSAoU0VMRUNUIHllYXJJRCwgQ09OQ0FUKG5hbWVGaXJzdCwgIiAiLCBuYW1lTGFzdCkgQVMgZnVsbE5hbWUsIHRlYW1JRCwgSCwgQUIsIChIL0FCKSBBUyBCYXR0aW5nX0F2ZXJhZ2UNCiAgICAgIEZST00gQmF0dGluZw0KICAgICAgSk9JTiBNQVNURVINCiAgICAgIE9OIEJhdHRpbmcucGxheWVySUQgPSBNQVNURVIucGxheWVySUQNCiAgICAgIFdIRVJFIHllYXJJRCA9IDE5ODAgQU5EIEFCID4gNDAwDQogICAgICBPUkRFUiBCWSBCYXR0aW5nX0F2ZXJhZ2UgREVTQw0KICAgICAgTElNSVQgMTApIGJhdG9wMTAgLyp0YWJsZSBhbGlhcyovDQpKT0lOIFRlYW1zIA0KT04gYmF0b3AxMC50ZWFtSUQgPSBUZWFtcy50ZWFtSUQgQU5EIGJhdG9wMTAueWVhcklEID0gVGVhbXMueWVhcklEDQpXSEVSRSBiYXRvcDEwLnllYXJJRCA9IDE5ODANCk9SREVSIEJZIGJhdG9wMTAuQmF0dGluZ19BdmVyYWdlIERFU0MNCmBgYA0KDQoxOTgwIGFsc28gc2F3IFtHZW9yZ2UgQnJldHRdKGh0dHA6Ly9iYXNlYmFsbGhhbGwub3JnL2hvZi9icmV0dC1nZW9yZ2UpLCB3aXRoIGEgMC4zOTAgYmF0dGluZyBhdmVyYWdlLCBjb21lIGNsb3NlIHRvIGpvaW5pbmcgdGhlIFswLjQwMCBmcmF0ZXJuaXR5XShodHRwOi8vd3d3LmJhc2ViYWxsLWFsbWFuYWMuY29tL2hpdHRpbmcvaGk0MDBjLnNodG1sKSwgb25lIHRoYXQgaGFzbid0IHdlbGNvbWVkIGFueSBuZXcgbWVtYmVycyBzaW5jZSBbMTk0MV0oaHR0cDovL3d3dy5oaXN0b3J5LmNvbS90aGlzLWRheS1pbi1oaXN0b3J5L3RlZC13aWxsaWFtcy1iZWNvbWVzLWxhc3QtcGxheWVyLXRvLWhpdC00MDApLiBTaW5jZSAxOTQxLCBvbmx5IFtUb255IEd3eW5uXShodHRwOi8vYmFzZWJhbGxoYWxsLm9yZy9ob2YvZ3d5bm4tdG9ueSkgaGFzIGNvbWUgY2xvc2VyIHRoYW4gQnJldHQgdG8gdGhlIDAuNDAwIG1hcmsuIEkgYWxzbyBoYXZlIGFuIGluZGVsaWJsZSBtZW1vcnkgb2YgR2VvcmdlIEJyZXR0IFsqKmZ1cmlvdXNseSoqIHN0b3JtaW5nIHRoZSBmaWVsZF0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1nYkVIQXNaeFJZbykgZHVyaW5nIHRoZSBbcGluZSB0YXIgaW5jaWRlbnQgb2YgMTk4M10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUGluZV9UYXJfSW5jaWRlbnQpLiBIaXMgS2Fuc2FzIENpdHkgUm95YWxzIHJlYWNoZWQgdGhlIFdvcmxkIFNlcmllcyBpbiAxOTgwLCB3aGVyZSB0aGV5IGxvc3QgdG8gdGhlIFBoaWxsaWVzLg0KDQoNCiFbXShHZW9yZ2VfQnJldHRfYmFzZWJhbGxfY2FyZC5KUEcgIkdlb3JnZSBCcmV0dCIpDQoNCiMjIyMgMi4zLjIgSGFsbCBvZiBGYW1lIGluZHVjdGVlcw0KQW5vdGhlciBxdWVyeSB3ZSBjYW4gYW5zd2VyIHVzaW5nIGEgam9pbjogV2hpY2ggcGxheWVycyBhY3RpdmUgaW4gMTk4MCB3ZW50IG9uIHRvIGpvaW4gQ29vcGVyc3Rvd24ncyBIYWxsIG9mIEZhbWU/IFNpbmNlIHBpdGNoZXJzIGFuZCBiYXR0ZXJzIGFyZSBrZXB0IGluIHNlcGFyYXRlIHRhYmxlcywgbGV0J3MgZG8gdGhlIGJhdHRlcnMgZmlyc3QuIFdlIGNhbiBkbyBhIGBKT0lOYCBiZXR3ZWVuIGEgdGFibGUgb2YgYmF0dGVycyBhY3RpdmUgaW4gMTk4MCBhbmQgYSB0YWJsZSBvZiBmaWVsZGVycyB3aG9zZSBwb3NpdGlvbiB3YXMgbm90IHBpdGNoZXIuIFdlIHVzZSB0aGUgYERJU1RJTkNUYCBmdW5jdGlvbiBmb3IgdGhpcyBzZWNvbmQgdGFibGUgYmVjYXVzZSBzb21lIHBsYXllcnMgcGxheWVkIG1vcmUgdGhhbiBvbmUgcG9zaXRpb24gaW4gMTk4MCBhbmQgdGhleSB3b3VsZCB0aGVyZWZvcmUgYmUgcmVwb3J0ZWQgbW9yZSB0aGFuIG9uY2UgaWYgd2UgZG9uJ3QgdXNlIGBESVNUSU5DVGAuIEZvciBleGFtcGxlLCBDYXJsdG9uIEZpc2sgcGxheWVkIGZpcnN0IGJhc2UsIHRoaXJkIGJhc2UsIG91dGZpZWxkZXIsIGFuZCBjYXRjaGVyIGluIDE5ODAuDQpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KU0VMRUNUIGJhdHRlcjE5ODAucGxheWVySUQNCkZST00gIChTRUxFQ1QgcGxheWVySUQgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA9IDE5ODApIGJhdHRlcjE5ODANCkpPSU4gKFNFTEVDVCBESVNUSU5DVChwbGF5ZXJJRCkgRlJPTSBGaWVsZGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwIEFORCBQb3MgPD4gIlAiKSBub3RQaXRjaGVyMTk4MA0KT04gYmF0dGVyMTk4MC5wbGF5ZXJJRCA9IG5vdFBpdGNoZXIxOTgwLnBsYXllcklEDQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRifQ0KU0VMRUNUIGJhdHRlcjE5ODAucGxheWVySUQNCkZST00gIChTRUxFQ1QgcGxheWVySUQgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA9IDE5ODApIGJhdHRlcjE5ODANCkpPSU4gKFNFTEVDVCBESVNUSU5DVChwbGF5ZXJJRCkgRlJPTSBGaWVsZGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwIEFORCBQb3MgPD4gIlAiKSBub3RQaXRjaGVyMTk4MA0KT04gYmF0dGVyMTk4MC5wbGF5ZXJJRCA9IG5vdFBpdGNoZXIxOTgwLnBsYXllcklEDQpgYGANCg0KVGhlbiB3ZSBjYW4gdGFrZSB0aGF0IHRhYmxlLCBhbGlhcyBpdCBhcyBiYXR0ZXJOb3RQaXRjaGVyMTk4MCBhbmQgYEpPSU5gIGl0IHRvIHRoZSBIYWxsT2ZGYW1lIHRhYmxlLCBmaWx0ZXJlZCB0byBpbmNsdWRlIGluZHVjdGVlcyBvbmx5LCBgT05gIHBsYXllcklELiBBZGRpdGlvbmFsbHksIGJlZm9yZSBwZXJmb3JtaW5nIHRoZSBgSk9JTmAsIHdlIGNhbiBjb21wdXRlIHRoZSBwZXJjZW50YWdlIG9mIHZvdGVycyByZWNlaXZlZCBieSB0aGUgaW5kdWN0ZWVzIGZyb20gdGhlIHNwb3J0c3dyaXRlcnMgdGhlIHllYXIgdGhleSB3ZXJlIGluZHVjdGVkLiBUaGUgdGhyZXNob2xkIGZvciBpbmR1Y3Rpb24gaXMgNzUlIG9mIHRoZSB2b3Rlcy4NCmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQpTRUxFQ1QgYmF0dGVyTm90UGl0Y2hlcjE5ODAucGxheWVySUQsIGhvZi5QZXJjZW50YWdlX29mX3ZvdGVzX3JlY2VpdmVkLCBob2YueWVhckluZHVjdGVkDQpGUk9NIChTRUxFQ1QgYmF0dGVyMTk4MC5wbGF5ZXJJRA0KICAgICAgRlJPTSAgKFNFTEVDVCBwbGF5ZXJJRCBGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCkgYmF0dGVyMTk4MA0KICAgICAgSk9JTiAoU0VMRUNUIERJU1RJTkNUKHBsYXllcklEKSBGUk9NIEZpZWxkaW5nIFdIRVJFIHllYXJJRCA9IDE5ODAgQU5EIFBvcyA8PiAiUCIpIG5vdFBpdGNoZXIxOTgwDQogICAgICBPTiBiYXR0ZXIxOTgwLnBsYXllcklEID0gbm90UGl0Y2hlcjE5ODAucGxheWVySUQpIGJhdHRlck5vdFBpdGNoZXIxOTgwDQpKT0lOIChTRUxFQ1QgMTAwLjAqKHZvdGVzL2JhbGxvdHMpIEFTIFBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQsIHBsYXllcklELCB5ZWFySUQgQVMgeWVhckluZHVjdGVkIEZST00gSGFsbE9mRmFtZSBXSEVSRSBpbmR1Y3RlZCA9ICJZIikgaG9mDQpPTiBob2YucGxheWVySUQgPSBiYXR0ZXJOb3RQaXRjaGVyMTk4MC5wbGF5ZXJJRA0KT1JERVIgQlkgaG9mLlBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQgREVTQw0KYGBgDQoNCmBgYHtzcWwgY29ubmVjdGlvbj1kYn0NClNFTEVDVCBiYXR0ZXJOb3RQaXRjaGVyMTk4MC5wbGF5ZXJJRCwgaG9mLlBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQsIGhvZi55ZWFySW5kdWN0ZWQNCkZST00gKFNFTEVDVCBiYXR0ZXIxOTgwLnBsYXllcklEDQogICAgICBGUk9NICAoU0VMRUNUIHBsYXllcklEIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwKSBiYXR0ZXIxOTgwDQogICAgICBKT0lOIChTRUxFQ1QgRElTVElOQ1QocGxheWVySUQpIEZST00gRmllbGRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCBBTkQgUG9zIDw+ICJQIikgbm90UGl0Y2hlcjE5ODANCiAgICAgIE9OIGJhdHRlcjE5ODAucGxheWVySUQgPSBub3RQaXRjaGVyMTk4MC5wbGF5ZXJJRCkgYmF0dGVyTm90UGl0Y2hlcjE5ODANCkpPSU4gKFNFTEVDVCAxMDAuMCoodm90ZXMvYmFsbG90cykgQVMgUGVyY2VudGFnZV9vZl92b3Rlc19yZWNlaXZlZCwgcGxheWVySUQsIHllYXJJRCBBUyB5ZWFySW5kdWN0ZWQgRlJPTSBIYWxsT2ZGYW1lIFdIRVJFIGluZHVjdGVkID0gIlkiKSBob2YNCk9OIGhvZi5wbGF5ZXJJRCA9IGJhdHRlck5vdFBpdGNoZXIxOTgwLnBsYXllcklEDQpPUkRFUiBCWSBob2YuUGVyY2VudGFnZV9vZl92b3Rlc19yZWNlaXZlZCBERVNDDQpgYGANCg0KVGhlbiB3ZSBjYW4gYEpPSU5gIHRoZSB0YWJsZSB3ZSBqdXN0IGdvdCB3aXRoIHRoZSBNQVNURVIgdGFibGUgdG8gZmluZCB0aGUgcGxheWVycycgbmFtZXMsIHVzaW5nIHRoZSBwbGF5ZXJJRCBsaWtlIHdlIGRpZCBiZWZvcmUuIFdlIGFyZSB1c2luZyBgRElTVElOQ1RgIGJlY2F1c2UgaWYgYSBwbGF5ZXIgcGxheWVkIGZvciBtb3JlIHRoYW4gb25lIHRlYW0gaW4gMTk4MCwgaGUgd2lsbCBhcHBlYXIgdHdpY2UgaW4gdGhlIE1BU1RFUiB0YWJsZSwgYW5kIGluIG91ciByZXN1bHRzLCB3aGljaCB3ZSBkb24ndCB3YW50LiBPbiB0aGUgcGl0Y2hlcnMgc2lkZSwgR2F5bG9yZCBQZXJyeSBwbGF5ZWQgZm9yIHR3byBkaWZmZXJlbnQgdGVhbXMgaW4gMTk4MC4NCmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQpTRUxFQ1QgRElTVElOQ1QoQ09OQ0FUKG5hbWVGaXJzdCwgIiAiLCBuYW1lTGFzdCkpIEFTIGZ1bGxOYW1lLCBob2YxOTgwQmF0dGluZy5QZXJjZW50YWdlX29mX3ZvdGVzX3JlY2VpdmVkLCBob2YxOTgwQmF0dGluZy55ZWFySW5kdWN0ZWQNCkZST00gKFNFTEVDVCBiYXR0ZXJOb3RQaXRjaGVyMTk4MC5wbGF5ZXJJRCwgaG9mLlBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQsIGhvZi55ZWFySW5kdWN0ZWQNCiAgICAgIEZST00gKFNFTEVDVCBiYXR0ZXIxOTgwLnBsYXllcklEDQogICAgICAgICAgICBGUk9NICAoU0VMRUNUIHBsYXllcklEIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwKSBiYXR0ZXIxOTgwDQogICAgICAgICAgICBKT0lOIChTRUxFQ1QgRElTVElOQ1QocGxheWVySUQpIEZST00gRmllbGRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCBBTkQgUG9zIDw+ICJQIikgbm90UGl0Y2hlcjE5ODANCiAgICAgICAgICAgIE9OIGJhdHRlcjE5ODAucGxheWVySUQgPSBub3RQaXRjaGVyMTk4MC5wbGF5ZXJJRCkgYmF0dGVyTm90UGl0Y2hlcjE5ODANCiAgICAgIEpPSU4gKFNFTEVDVCAxMDAuMCoodm90ZXMvYmFsbG90cykgQVMgUGVyY2VudGFnZV9vZl92b3Rlc19yZWNlaXZlZCwgcGxheWVySUQsIHllYXJJRCBBUyB5ZWFySW5kdWN0ZWQgRlJPTSBIYWxsT2ZGYW1lIFdIRVJFIGluZHVjdGVkID0gIlkiKSBob2YNCiAgICAgIE9OIGhvZi5wbGF5ZXJJRCA9IGJhdHRlck5vdFBpdGNoZXIxOTgwLnBsYXllcklEDQogICAgICBPUkRFUiBCWSBob2YuUGVyY2VudGFnZV9vZl92b3Rlc19yZWNlaXZlZCBERVNDKSBob2YxOTgwQmF0dGluZw0KSk9JTiBNQVNURVINCk9OIGhvZjE5ODBCYXR0aW5nLnBsYXllcklEID0gTUFTVEVSLnBsYXllcklEDQpPUkRFUiBCWSBob2YxOTgwQmF0dGluZy5QZXJjZW50YWdlX29mX3ZvdGVzX3JlY2VpdmVkIERFU0MNCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJ9DQpTRUxFQ1QgRElTVElOQ1QoQ09OQ0FUKG5hbWVGaXJzdCwgIiAiLCBuYW1lTGFzdCkpIEFTIGZ1bGxOYW1lLCBob2YxOTgwQmF0dGluZy5QZXJjZW50YWdlX29mX3ZvdGVzX3JlY2VpdmVkLCBob2YxOTgwQmF0dGluZy55ZWFySW5kdWN0ZWQNCkZST00gKFNFTEVDVCBiYXR0ZXJOb3RQaXRjaGVyMTk4MC5wbGF5ZXJJRCwgaG9mLlBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQsIGhvZi55ZWFySW5kdWN0ZWQNCiAgICAgIEZST00gKFNFTEVDVCBiYXR0ZXIxOTgwLnBsYXllcklEDQogICAgICAgICAgICBGUk9NICAoU0VMRUNUIHBsYXllcklEIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwKSBiYXR0ZXIxOTgwDQogICAgICAgICAgICBKT0lOIChTRUxFQ1QgRElTVElOQ1QocGxheWVySUQpIEZST00gRmllbGRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCBBTkQgUG9zIDw+ICJQIikgbm90UGl0Y2hlcjE5ODANCiAgICAgICAgICAgIE9OIGJhdHRlcjE5ODAucGxheWVySUQgPSBub3RQaXRjaGVyMTk4MC5wbGF5ZXJJRCkgYmF0dGVyTm90UGl0Y2hlcjE5ODANCiAgICAgIEpPSU4gKFNFTEVDVCAxMDAuMCoodm90ZXMvYmFsbG90cykgQVMgUGVyY2VudGFnZV9vZl92b3Rlc19yZWNlaXZlZCwgcGxheWVySUQsIHllYXJJRCBBUyB5ZWFySW5kdWN0ZWQgRlJPTSBIYWxsT2ZGYW1lIFdIRVJFIGluZHVjdGVkID0gIlkiKSBob2YNCiAgICAgIE9OIGhvZi5wbGF5ZXJJRCA9IGJhdHRlck5vdFBpdGNoZXIxOTgwLnBsYXllcklEDQogICAgICBPUkRFUiBCWSBob2YuUGVyY2VudGFnZV9vZl92b3Rlc19yZWNlaXZlZCBERVNDKSBob2YxOTgwQmF0dGluZw0KSk9JTiBNQVNURVINCk9OIGhvZjE5ODBCYXR0aW5nLnBsYXllcklEID0gTUFTVEVSLnBsYXllcklEDQpPUkRFUiBCWSBob2YxOTgwQmF0dGluZy5QZXJjZW50YWdlX29mX3ZvdGVzX3JlY2VpdmVkIERFU0MNCmBgYA0KDQpbVGltIFJhaW5lc10oaHR0cDovL2Jhc2ViYWxsaGFsbC5vcmcvaG9mL3JhaW5lcy10aW0pISBIZSB3YXMgbm90IGVsZWN0ZWQgdW50aWwgKioyMDE3KiosIGhpcyBsYXN0IHllYXIgb2YgZWxpZ2liaWxpdHkuIFNvbWUgaGF2ZSBbc3VnZ2VzdGVkXShodHRwczovL2ZpdmV0aGlydHllaWdodC5jb20vZmVhdHVyZXMvc2FiZXJtZXRyaWNzLWhlbHBlZC1wdXQtdGltLXJhaW5lcy1pbi10aGUtaGFsbC1vZi1mYW1lLykgdGhhdCBoaXMgaW5kdWN0aW9uIG1heSBoYXZlIGJlZW4gcGFydGx5IGR1ZSB0byBhIG1vcmUgc29waGlzdGljYXRlZCB1bmRlcnN0YW5kaW5nIG9mIHNhYmVybWV0cmljcy4gR29vZCBmb3IgaGltISBbUmlja2V5IEhlbmRlcnNvbl0oaHR0cDovL2Jhc2ViYWxsaGFsbC5vcmcvaG9mL2hlbmRlcnNvbi1yaWNrZXkpISBObyBvbmUgaXMgcHJvdWRlciBvZiBSaWNrZXkgdGhhbiBSaWNrZXksIFt0aGUgZ3JlYXRlc3RdKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9WENSeV9mSzhmdTgpLCBvZiBhbGwgdGltZSEgSSByZW1lbWJlciBhIGNhdGNoZXIgY291bGQgKipyZWFsbHkqKiBtYWtlIGEgbmFtZSBmb3IgaGltc2VsZiBpZiBoZSBjYXVnaHQgUmlja2V5IHN0ZWFsaW5nLiBSaWNrZXkgc3RvbGUgMTAwIGJhc2VzIGluIDE5ODAsIGFuZCAxMzAgaW4gMTk4Mi4gSSBhbHNvIHJlbWVtYmVyIHRoZSBncmFjZWZ1bG5lc3Mgb2YgW096emllIFNtaXRoIF0oaHR0cDovL2Jhc2ViYWxsaGFsbC5vcmcvaG9mL3NtaXRoLW96emllKSwgdGhlIFdpemFyZCBvZiBPei4NCg0KDQohW10oVGltX1JhaW5lc19iYXNlYmFsbF9jYXJkLkpQRyAiVGltIFJhaW5lcyIpIVtdKFJpY2tleV9IZW5kZXJzb25fYmFzZWJhbGxfY2FyZC5KUEcgIlJpY2tleSIpIVtdKE96emllX1NtaXRoX2Jhc2ViYWxsX2NhcmQuSlBHICJUaGUgV2l6YXJkIikNCg0KDQpOb3cgd2UgZG8gaXQgZm9yIHRoZSBwaXRjaGVycywgaW4gYSBzaW5nbGUgc3RlcDoNCmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQpTRUxFQ1QgRElTVElOQ1QoQ09OQ0FUKG5hbWVGaXJzdCwgIiAiLCBuYW1lTGFzdCkpIEFTIGZ1bGxOYW1lLCBob2YxOTgwUGl0Y2hpbmcuUGVyY2VudGFnZV9vZl92b3Rlc19yZWNlaXZlZCwgaG9mMTk4MFBpdGNoaW5nLnllYXJJbmR1Y3RlZA0KRlJPTSAoU0VMRUNUIHBpdGNoZXJOb3RCYXR0ZXIxOTgwLnBsYXllcklELCBob2YuUGVyY2VudGFnZV9vZl92b3Rlc19yZWNlaXZlZCwgaG9mLnllYXJJbmR1Y3RlZA0KICAgICAgRlJPTSAoU0VMRUNUIHBpdGNoZXIxOTgwLnBsYXllcklEDQogICAgICAgICAgICBGUk9NICAoU0VMRUNUIHBsYXllcklEIEZST00gUGl0Y2hpbmcgV0hFUkUgeWVhcklEID0gMTk4MCkgcGl0Y2hlcjE5ODANCiAgICAgICAgICAgIEpPSU4gKFNFTEVDVCBESVNUSU5DVChwbGF5ZXJJRCkgRlJPTSBGaWVsZGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwIEFORCBQb3MgPSAiUCIpIG9ubHlQaXRjaGVyMTk4MA0KICAgICAgICAgICAgT04gcGl0Y2hlcjE5ODAucGxheWVySUQgPSBvbmx5UGl0Y2hlcjE5ODAucGxheWVySUQpIHBpdGNoZXJOb3RCYXR0ZXIxOTgwDQogICAgICBKT0lOIChTRUxFQ1QgMTAwLjAqKHZvdGVzL2JhbGxvdHMpIEFTIFBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQsIHBsYXllcklELCB5ZWFySUQgQVMgeWVhckluZHVjdGVkIEZST00gSGFsbE9mRmFtZSBXSEVSRSBpbmR1Y3RlZCA9ICJZIikgaG9mDQogICAgICBPTiBob2YucGxheWVySUQgPSBwaXRjaGVyTm90QmF0dGVyMTk4MC5wbGF5ZXJJRA0KICAgICAgT1JERVIgQlkgaG9mLlBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQgREVTQykgaG9mMTk4MFBpdGNoaW5nDQpKT0lOIE1BU1RFUg0KT04gaG9mMTk4MFBpdGNoaW5nLnBsYXllcklEID0gTUFTVEVSLnBsYXllcklEDQpPUkRFUiBCWSBob2YxOTgwUGl0Y2hpbmcuUGVyY2VudGFnZV9vZl92b3Rlc19yZWNlaXZlZCBERVNDDQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRifQ0KU0VMRUNUIERJU1RJTkNUKENPTkNBVChuYW1lRmlyc3QsICIgIiwgbmFtZUxhc3QpKSBBUyBmdWxsTmFtZSwgaG9mMTk4MFBpdGNoaW5nLlBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQsIGhvZjE5ODBQaXRjaGluZy55ZWFySW5kdWN0ZWQNCkZST00gKFNFTEVDVCBwaXRjaGVyTm90QmF0dGVyMTk4MC5wbGF5ZXJJRCwgaG9mLlBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQsIGhvZi55ZWFySW5kdWN0ZWQNCiAgICAgIEZST00gKFNFTEVDVCBwaXRjaGVyMTk4MC5wbGF5ZXJJRA0KICAgICAgICAgICAgRlJPTSAgKFNFTEVDVCBwbGF5ZXJJRCBGUk9NIFBpdGNoaW5nIFdIRVJFIHllYXJJRCA9IDE5ODApIHBpdGNoZXIxOTgwDQogICAgICAgICAgICBKT0lOIChTRUxFQ1QgRElTVElOQ1QocGxheWVySUQpIEZST00gRmllbGRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCBBTkQgUG9zID0gIlAiKSBvbmx5UGl0Y2hlcjE5ODANCiAgICAgICAgICAgIE9OIHBpdGNoZXIxOTgwLnBsYXllcklEID0gb25seVBpdGNoZXIxOTgwLnBsYXllcklEKSBwaXRjaGVyTm90QmF0dGVyMTk4MA0KICAgICAgSk9JTiAoU0VMRUNUIDEwMC4wKih2b3Rlcy9iYWxsb3RzKSBBUyBQZXJjZW50YWdlX29mX3ZvdGVzX3JlY2VpdmVkLCBwbGF5ZXJJRCwgeWVhcklEIEFTIHllYXJJbmR1Y3RlZCBGUk9NIEhhbGxPZkZhbWUgV0hFUkUgaW5kdWN0ZWQgPSAiWSIpIGhvZg0KICAgICAgT04gaG9mLnBsYXllcklEID0gcGl0Y2hlck5vdEJhdHRlcjE5ODAucGxheWVySUQNCiAgICAgIE9SREVSIEJZIGhvZi5QZXJjZW50YWdlX29mX3ZvdGVzX3JlY2VpdmVkIERFU0MpIGhvZjE5ODBQaXRjaGluZw0KSk9JTiBNQVNURVINCk9OIGhvZjE5ODBQaXRjaGluZy5wbGF5ZXJJRCA9IE1BU1RFUi5wbGF5ZXJJRA0KT1JERVIgQlkgaG9mMTk4MFBpdGNoaW5nLlBlcmNlbnRhZ2Vfb2Zfdm90ZXNfcmVjZWl2ZWQgREVTQw0KYGBgDQoNCg0KW1RvbSBTZWF2ZXJdKGh0dHA6Ly9iYXNlYmFsbGhhbGwub3JnL2hvZi9zZWF2ZXItdG9tKSBoZWxkIHRoZSByZWNvcmQgZm9yIHRoZSBoaWdoZXN0IHZvdGluZyBwZXJjZW50YWdlIHJlY2VpdmVkIGZyb20gdGhlIHNwb3J0c3dyaXRlcnMgdG8gZW50ZXIgdGhlIEhhbGwgb2YgRmFtZSB1bnRpbCBbS2VuIEdyaWZmZXkgSnIuXShodHRwOi8vYmFzZWJhbGxoYWxsLm9yZy9ob2YvZ3JpZmZleS1qci1rZW4pIGJyb2tlIGl0IGluIDIwMTYuIFtOb2xhbiBSeWFuXShodHRwOi8vYmFzZWJhbGxoYWxsLm9yZy9ob2Yvcnlhbi1ub2xhbiksIHdobyBoYXMgYXQgbGVhc3QgdGhyZWUgcmVjb3JkcyB0aGF0IHByb2JhYmx5IHdpbGwgbmV2ZXIgYmUgdG9wcGVkOiA1LDcxNCBjYXJlZXIgc3RyaWtlb3V0cywgNyBjYXJlZXIgbm8taGl0dGVycywgYW5kIDM4MyBzdHJpa2VvdXRzIGluIGEgc2luZ2xlIHNlYXNvbiwgcmFua3MgdGhpcmQgaW4gcGVyY2VudGFnZSBvZiB2b3RlcyByZWNlaXZlZCB0byBDb29wZXJzdG93biwgYmVoaW5kIFNlYXZlciBhbmQgR3JpZmZleS4gW1N0ZXZlIENhcmx0b25dKGh0dHA6Ly9iYXNlYmFsbGhhbGwub3JnL2hvZi9jYXJsdG9uLXN0ZXZlKSB3b24gMiBnYW1lcyBpbiB0aGUgMTk4MCBXb3JsZCBTZXJpZXMgcGxheWluZyBmb3IgdGhlIFBoaWxsaWVzLCBhIFNlcmllcyB0aGV5IHdvbi4gSGlzIDMwNCBpbm5pbmdzIHBpdGNoZWQgaW4gMTk4MCB3ZXJlIFt0aGUgbGFzdCB0aW1lIGFueW9uZSBwaXRjaGVkIDMwMCBvciBtb3JlXShodHRwOi8vd3d3LmVzcG4uY29tL2Jsb2cvc3dlZXRzcG90L3Bvc3QvXy9pZC8xMjgyMC90aGUtYmVzdC1waXRjaGluZy1zZWFzb25zLXNpbmNlLTE5NjApLiBIZSBsZWQgdGhlIE5MIGluIHdpbnMgKDI0KSwgaW5uaW5ncywgYW5kIHN0cmlrZW91dHMgKDI4NikgdGhhdCB5ZWFyLCBhbmQgd29uIHRoZSBOTCBDeSBZb3VuZyBhd2FyZCBhcyB3ZWxsLg0KDQoNCiFbXShUb21fU2VhdmVyX2Jhc2ViYWxsX2NhcmQuSlBHICJUb20gU2VhdmVyIikhW10oTm9sYW5fUnlhbl9iYXNlYmFsbF9jYXJkLkpQRyAiTm9sYW4gUnlhbiIpIVtdKFN0ZXZlX0Nhcmx0b25fYmFzZWJhbGxfY2FyZC5KUEcgIlN0ZXZlIENhcmx0b24iKQ0KDQojIyMgMi40IFVzaW5nIGBHUk9VUCBCWWANCiMjIyMgMi40LjEgVG9wIGhvbWUgcnVuIGhpdHRlcnMgYnkgcG9zaXRpb24gaW4gMTk4MA0KU3VwcG9zZSB3ZSB3YW50IHRvIGtub3cgdGhlIHRvcCBob21lIHJ1biBoaXR0ZXJzIGJ5IHBvc2l0aW9uIGluIDE5ODAsIGUuZy4sIHdoaWNoIGZpcnN0IGJhc2VtYW4gaGl0IG1vcmUgaG9tZSBydW5zIHRoYW4gYW55IG90aGVyPyBXZSB3aWxsIGRvIGl0IGJ5IHN0ZXBzLCBhcyB3ZSBidWlsdCB0aGUgZWFybGllciBxdWVyaWVzLiBXZSB3aWxsIGZpcnN0IGNyZWF0ZSBhIHRhYmxlIGJ5IGpvaW5pbmcgdGhlIEJhdHRpbmcgYW5kIEZpZWxkaW5nIHRhYmxlcyBmb3IgMTk4MA0KYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NClNFTEVDVCBocjE5ODAucGxheWVySUQsIGhyMTk4MC5ociwgcG9zMTk4MC5Qb3MNCkZST00gKFNFTEVDVCBwbGF5ZXJJRCwgaHIgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA9IDE5ODApIGhyMTk4MA0KSk9JTiAoU0VMRUNUIHBsYXllcklELCBQb3MgRlJPTSBGaWVsZGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwICkgcG9zMTk4MA0KT04gaHIxOTgwLnBsYXllcklEID0gcG9zMTk4MC5wbGF5ZXJJRA0KYGBgDQoNCmBgYHtzcWwgY29ubmVjdGlvbj1kYn0NClNFTEVDVCBocjE5ODAucGxheWVySUQsIGhyMTk4MC5ociwgcG9zMTk4MC5Qb3MNCkZST00gKFNFTEVDVCBwbGF5ZXJJRCwgaHIgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA9IDE5ODApIGhyMTk4MA0KSk9JTiAoU0VMRUNUIHBsYXllcklELCBQb3MgRlJPTSBGaWVsZGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwICkgcG9zMTk4MA0KT04gaHIxOTgwLnBsYXllcklEID0gcG9zMTk4MC5wbGF5ZXJJRA0KYGBgDQoNCg0KVGhlbiB3ZSBjcmVhdGUgYSB0YWJsZSB0aGF0IG91dHB1dHMgdGhlIG1heGltdW0gaG9tZSBydW5zIGJ5IHBvc2l0aW9uLCB1c2luZyBgR1JPVVAgQllgLg0KYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NClNFTEVDVCBNQVgoaHIxOTgwLmhyKSBhcyBtYXhfaHIsIHBvczE5ODAuUG9zDQpGUk9NIChTRUxFQ1QgcGxheWVySUQsIGhyIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwKSBocjE5ODANCkpPSU4gKFNFTEVDVCBwbGF5ZXJJRCwgUG9zIEZST00gRmllbGRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCApIHBvczE5ODANCk9OIGhyMTk4MC5wbGF5ZXJJRCA9IHBvczE5ODAucGxheWVySUQNCkdST1VQIEJZIHBvczE5ODAuUG9zDQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRifQ0KU0VMRUNUIE1BWChocjE5ODAuaHIpIGFzIG1heF9ociwgcG9zMTk4MC5Qb3MNCkZST00gKFNFTEVDVCBwbGF5ZXJJRCwgaHIgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA9IDE5ODApIGhyMTk4MA0KSk9JTiAoU0VMRUNUIHBsYXllcklELCBQb3MgRlJPTSBGaWVsZGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwICkgcG9zMTk4MA0KT04gaHIxOTgwLnBsYXllcklEID0gcG9zMTk4MC5wbGF5ZXJJRA0KR1JPVVAgQlkgcG9zMTk4MC5Qb3MNCmBgYA0KDQoNClRoZXJlIGFyZSBzZXZlbiBmaWVsZGluZyBwb3NpdGlvbnMsIHNvIHdlIGp1c3QgaGF2ZSB0aGUgaGlnaGVzdCBob21lIHJ1biB0b3RhbHMgYXQgZWFjaCBwb3NpdGlvbi4gVGhlbiB3ZSB0YWtlIHRoZSB0d28gbWFudWZhY3R1cmVkIHRhYmxlcyBhbmQgYEpPSU5gIHRoZW0gb24gdHdvIGZpZWxkczogcGxheWVyIHBvc2l0aW9uIGFuZCBob21lIHJ1bnMuIFRoZSBmaXJzdCB0YWJsZSB3aWxsIG1hdGNoIHRoZSBzZWNvbmQgb25seSB3aGVyZSBob21lIHJ1bnMgYXJlIGhpZ2hlc3QsIGF0IGVhY2ggcG9zaXRpb24uDQpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KU0VMRUNUIHBsYXllcklELCBwb3NUYWJsZS5ociBhcyBob21lX3J1bnMsIHBvc1RhYmxlLlBvcyBhcyBQb3NpdGlvbg0KRlJPTSAoU0VMRUNUIGhyMTk4MC5wbGF5ZXJJRCwgaHIxOTgwLmhyLCBwb3MxOTgwLlBvcw0KICAgICAgRlJPTSAoU0VMRUNUIHBsYXllcklELCBociBGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCkgaHIxOTgwDQogICAgICBKT0lOIChTRUxFQ1QgcGxheWVySUQsIFBvcyBGUk9NIEZpZWxkaW5nIFdIRVJFIHllYXJJRCA9IDE5ODAgKSBwb3MxOTgwDQogICAgICBPTiBocjE5ODAucGxheWVySUQgPSBwb3MxOTgwLnBsYXllcklEKSBwb3NUYWJsZQ0KSk9JTiAoU0VMRUNUIE1BWChocjE5ODAuaHIpIGFzIG1heF9ociwgcG9zMTk4MC5Qb3MNCiAgICAgIEZST00gKFNFTEVDVCBwbGF5ZXJJRCwgaHIgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA9IDE5ODApIGhyMTk4MA0KICAgICAgSk9JTiAoU0VMRUNUIHBsYXllcklELCBQb3MgRlJPTSBGaWVsZGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwICkgcG9zMTk4MA0KICAgICAgT04gaHIxOTgwLnBsYXllcklEID0gcG9zMTk4MC5wbGF5ZXJJRA0KICAgICAgR1JPVVAgQlkgcG9zMTk4MC5Qb3MpIHBvc1RhYmxlTWF4DQpPTiBwb3NUYWJsZS5Qb3MgPSBwb3NUYWJsZU1heC5Qb3MgQU5EIHBvc1RhYmxlLmhyID0gcG9zVGFibGVNYXgubWF4X2hyDQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRifQ0KU0VMRUNUIHBsYXllcklELCBwb3NUYWJsZS5ociBhcyBob21lX3J1bnMsIHBvc1RhYmxlLlBvcyBhcyBQb3NpdGlvbg0KRlJPTSAoU0VMRUNUIGhyMTk4MC5wbGF5ZXJJRCwgaHIxOTgwLmhyLCBwb3MxOTgwLlBvcw0KICAgICAgRlJPTSAoU0VMRUNUIHBsYXllcklELCBociBGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCkgaHIxOTgwDQogICAgICBKT0lOIChTRUxFQ1QgcGxheWVySUQsIFBvcyBGUk9NIEZpZWxkaW5nIFdIRVJFIHllYXJJRCA9IDE5ODAgKSBwb3MxOTgwDQogICAgICBPTiBocjE5ODAucGxheWVySUQgPSBwb3MxOTgwLnBsYXllcklEKSBwb3NUYWJsZQ0KSk9JTiAoU0VMRUNUIE1BWChocjE5ODAuaHIpIGFzIG1heF9ociwgcG9zMTk4MC5Qb3MNCiAgICAgIEZST00gKFNFTEVDVCBwbGF5ZXJJRCwgaHIgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA9IDE5ODApIGhyMTk4MA0KICAgICAgSk9JTiAoU0VMRUNUIHBsYXllcklELCBQb3MgRlJPTSBGaWVsZGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwICkgcG9zMTk4MA0KICAgICAgT04gaHIxOTgwLnBsYXllcklEID0gcG9zMTk4MC5wbGF5ZXJJRA0KICAgICAgR1JPVVAgQlkgcG9zMTk4MC5Qb3MpIHBvc1RhYmxlTWF4DQpPTiBwb3NUYWJsZS5Qb3MgPSBwb3NUYWJsZU1heC5Qb3MgQU5EIHBvc1RhYmxlLmhyID0gcG9zVGFibGVNYXgubWF4X2hyDQpgYGANCg0KDQpGaW5hbGx5LCB3ZSBkbyB0aGUgYEpPSU5gIHdpdGggdGhlIE1BU1RFUiB0YWJsZSB0byBnZXQgdGhlIHBsYXllcnMnIG5hbWVzOg0KYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NClNFTEVDVCBESVNUSU5DVChDT05DQVQobmFtZUZpcnN0LCAiICIsIG5hbWVMYXN0KSkgQVMgZnVsbE5hbWUsIGhvbWVfcnVucywgUG9zaXRpb24NCkZST00gKFNFTEVDVCBwbGF5ZXJJRCwgcG9zVGFibGUuaHIgYXMgaG9tZV9ydW5zLCBwb3NUYWJsZS5Qb3MgYXMgUG9zaXRpb24NCiAgICAgIEZST00gKFNFTEVDVCBocjE5ODAucGxheWVySUQsIGhyMTk4MC5ociwgcG9zMTk4MC5Qb3MNCiAgICAgICAgICAgIEZST00gKFNFTEVDVCBwbGF5ZXJJRCwgaHIgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA9IDE5ODApIGhyMTk4MA0KICAgICAgICAgICAgSk9JTiAoU0VMRUNUIHBsYXllcklELCBQb3MgRlJPTSBGaWVsZGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwICkgcG9zMTk4MA0KICAgICAgICAgICAgT04gaHIxOTgwLnBsYXllcklEID0gcG9zMTk4MC5wbGF5ZXJJRCkgcG9zVGFibGUNCiAgICAgIEpPSU4gKFNFTEVDVCBNQVgoaHIxOTgwLmhyKSBhcyBtYXhfaHIsIHBvczE5ODAuUG9zDQogICAgICAgICAgICBGUk9NIChTRUxFQ1QgcGxheWVySUQsIGhyIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwKSBocjE5ODANCiAgICAgICAgICAgIEpPSU4gKFNFTEVDVCBwbGF5ZXJJRCwgUG9zIEZST00gRmllbGRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCApIHBvczE5ODANCiAgICAgICAgICAgIE9OIGhyMTk4MC5wbGF5ZXJJRCA9IHBvczE5ODAucGxheWVySUQNCiAgICAgICAgICAgIEdST1VQIEJZIHBvczE5ODAuUG9zKSBwb3NUYWJsZU1heA0KICAgICAgT04gcG9zVGFibGUuUG9zID0gcG9zVGFibGVNYXguUG9zIEFORCBwb3NUYWJsZS5ociA9IHBvc1RhYmxlTWF4Lm1heF9ocikgbWF4SHJCeVBvc2l0aW9uDQpKT0lOIE1BU1RFUg0KT04gTUFTVEVSLnBsYXllcklEID0gbWF4SHJCeVBvc2l0aW9uLnBsYXllcklEDQpPUkRFUiBCWSBtYXhIckJ5UG9zaXRpb24uaG9tZV9ydW5zIERFU0MNCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJ9DQpTRUxFQ1QgRElTVElOQ1QoQ09OQ0FUKG5hbWVGaXJzdCwgIiAiLCBuYW1lTGFzdCkpIEFTIGZ1bGxOYW1lLCBob21lX3J1bnMsIFBvc2l0aW9uDQpGUk9NIChTRUxFQ1QgcGxheWVySUQsIHBvc1RhYmxlLmhyIGFzIGhvbWVfcnVucywgcG9zVGFibGUuUG9zIGFzIFBvc2l0aW9uDQogICAgICBGUk9NIChTRUxFQ1QgaHIxOTgwLnBsYXllcklELCBocjE5ODAuaHIsIHBvczE5ODAuUG9zDQogICAgICAgICAgICBGUk9NIChTRUxFQ1QgcGxheWVySUQsIGhyIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPSAxOTgwKSBocjE5ODANCiAgICAgICAgICAgIEpPSU4gKFNFTEVDVCBwbGF5ZXJJRCwgUG9zIEZST00gRmllbGRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCApIHBvczE5ODANCiAgICAgICAgICAgIE9OIGhyMTk4MC5wbGF5ZXJJRCA9IHBvczE5ODAucGxheWVySUQpIHBvc1RhYmxlDQogICAgICBKT0lOIChTRUxFQ1QgTUFYKGhyMTk4MC5ocikgYXMgbWF4X2hyLCBwb3MxOTgwLlBvcw0KICAgICAgICAgICAgRlJPTSAoU0VMRUNUIHBsYXllcklELCBociBGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCkgaHIxOTgwDQogICAgICAgICAgICBKT0lOIChTRUxFQ1QgcGxheWVySUQsIFBvcyBGUk9NIEZpZWxkaW5nIFdIRVJFIHllYXJJRCA9IDE5ODAgKSBwb3MxOTgwDQogICAgICAgICAgICBPTiBocjE5ODAucGxheWVySUQgPSBwb3MxOTgwLnBsYXllcklEDQogICAgICAgICAgICBHUk9VUCBCWSBwb3MxOTgwLlBvcykgcG9zVGFibGVNYXgNCiAgICAgIE9OIHBvc1RhYmxlLlBvcyA9IHBvc1RhYmxlTWF4LlBvcyBBTkQgcG9zVGFibGUuaHIgPSBwb3NUYWJsZU1heC5tYXhfaHIpIG1heEhyQnlQb3NpdGlvbg0KSk9JTiBNQVNURVINCk9OIE1BU1RFUi5wbGF5ZXJJRCA9IG1heEhyQnlQb3NpdGlvbi5wbGF5ZXJJRA0KT1JERVIgQlkgbWF4SHJCeVBvc2l0aW9uLmhvbWVfcnVucyBERVNDDQpgYGANCg0KR3JlYXQhIFRoZXJlIHdhcyBhIHRpZSBhdCB0aGUgb3V0ZmllbGRlciBwb3NpdGlvbiBiZXR3ZWVuIEJlbiBPZ2xpdmllIGFuZCBSZWdnaWUgSmFja3Nvbi4gV2Ugc2VlIGJlbG92ZWQgSGFsbCBvZiBGYW1lcnMgW0dhcnkgQ2FydGVyXShodHRwOi8vYmFzZWJhbGxoYWxsLm9yZy9ob2YvY2FydGVyLWdhcnkpIGF0IGNhdGNoZXIgYW5kIFtSb2JpbiBZb3VudF0oaHR0cDovL2Jhc2ViYWxsaGFsbC5vcmcvaG9mL3lvdW50LXJvYmluKSBhdCBzaG9ydHN0b3AuIENhcnRlciB3YXMgYSBrZXkgcGxheWVyIG9mIHRoZSBOZXcgWW9yayBNZXRzIGluIDE5ODYsIHdoZW4gdGhleSB3b24gdGhlIFdvcmxkIFNlcmllcy4gWW91bnQgcGxheWVkIGhpcyBlbnRpcmUgY2FyZWVyIHdpdGggdGhlIE1pbHdhdWtlZSBCdWNrcy4gSW4gMTk4MiwgaGUgd2FzIG5hbWVkIE1WUCBvZiB0aGUgQW1lcmljYW4gTGVhZ3VlIGFmdGVyIHJlY2VpdmluZyBbMjcgb3V0IG9mIDI4XShodHRwOi8vd3d3LmJhc2ViYWxsLXJlZmVyZW5jZS5jb20vYXdhcmRzL2F3YXJkc18xOTgyLnNodG1sKSBmaXJzdC1wbGFjZSB2b3RlcyBmcm9tIHRoZSB3cml0ZXJzLg0KDQojIyMjIDIuNC4yIEhvbWUgcnVuIGxlYWRlcnMgb2YgdGhlIGVpZ2h0aWVzDQoNCldlIGNhbiBmaW5kIG91dCB0aGUgaG9tZSBydW4gbGVhZGVycyBieSB5ZWFyIHRocm91Z2hvdXQgdGhlIGVpZ2h0aWVzIHVzaW5nIHRoZSBzYW1lIGBHUk9VUCBCWWAgY29uc3RydWN0LiBTdGFydCBieSBmaW5kaW5nIHRoZSBtYXhpbXVtIG51bWJlciBvZiBob21lIHJ1bnMgaGl0IGJ5IHllYXIgZm9yIGVhY2ggeWVhciBvZiB0aGUgZGVjYWRlLg0KYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NClNFTEVDVCBNQVgoaHJFaWdodGllcy5ocikgYXMgbWF4X2hyLCB5ZWFySUQNCkZST00gKFNFTEVDVCB5ZWFySUQsIHBsYXllcklELCBociBGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEID4gMTk3OSBBTkQgeWVhcklEIDwgMTk5MCkgaHJFaWdodGllcw0KR1JPVVAgQlkgeWVhcklEDQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRifQ0KU0VMRUNUIE1BWChockVpZ2h0aWVzLmhyKSBhcyBtYXhfaHIsIHllYXJJRA0KRlJPTSAoU0VMRUNUIHllYXJJRCwgcGxheWVySUQsIGhyIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPiAxOTc5IEFORCB5ZWFySUQgPCAxOTkwKSBockVpZ2h0aWVzDQpHUk9VUCBCWSB5ZWFySUQNCmBgYA0KDQoNClRoZW4gY3JlYXRlIGEgdGFibGUgb2YgaG9tZSBydW5zIG9mIGV2ZXJ5IHBsYXllciB0aGF0IGJhdHRlZCBpbiB0aGUgZWlnaHRpZXMuDQpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KU0VMRUNUIHllYXJJRCwgcGxheWVySUQsIHRlYW1JRCwgaHIgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA+IDE5NzkgQU5EIHllYXJJRCA8IDE5OTANCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJ9DQpTRUxFQ1QgeWVhcklELCBwbGF5ZXJJRCwgdGVhbUlELCBociBGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEID4gMTk3OSBBTkQgeWVhcklEIDwgMTk5MA0KYGBgDQoNCk5vdyBgSk9JTmAgdGhlIHR3byB0YWJsZXMgYE9OYCBob21lIHJ1bnMgYW5kIHllYXIuIFdlIGdldCBtb3JlIHRoYW4gMTAgcmVzdWx0cyBiZWNhdXNlIG9mIHRoZSB0aWVzLiBJbiAxOTgyLCBmb3IgZXhhbXBsZSwgUmVnZ2llIEphY2tzb24gYW5kIEdvcm1hbiBUaG9tYXMgd2VyZSB0aWVkIGZvciB0aGUgbGVhZCB3aXRoIDM5IGhvbWUgcnVucyBlYWNoLg0KYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NClNFTEVDVCBockVpZ2h0aWVzVGFibGUueWVhcklEIGFzIHllYXIsIHBsYXllcklELCB0ZWFtSUQsIGhyRWlnaHRpZXNUYWJsZS5ocg0KRlJPTSAoU0VMRUNUIHllYXJJRCwgcGxheWVySUQsIHRlYW1JRCwgaHIgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA+IDE5NzkgQU5EIHllYXJJRCA8IDE5OTApIGhyRWlnaHRpZXNUYWJsZQ0KSk9JTiAoU0VMRUNUIE1BWChockVpZ2h0aWVzLmhyKSBhcyBtYXhfaHIsIHllYXJJRA0KICAgICAgRlJPTSAoU0VMRUNUIHllYXJJRCwgcGxheWVySUQsIGhyIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPiAxOTc5IEFORCB5ZWFySUQgPCAxOTkwKSBockVpZ2h0aWVzDQogICAgICBHUk9VUCBCWSB5ZWFySUQpIGhyRWlnaHRpZXNUYWJsZU1heA0KT04gaHJFaWdodGllc1RhYmxlLnllYXJJRCA9IGhyRWlnaHRpZXNUYWJsZU1heC55ZWFySUQgQU5EIGhyRWlnaHRpZXNUYWJsZS5ociA9IGhyRWlnaHRpZXNUYWJsZU1heC5tYXhfaHINCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJ9DQpTRUxFQ1QgaHJFaWdodGllc1RhYmxlLnllYXJJRCBhcyB5ZWFyLCBwbGF5ZXJJRCwgdGVhbUlELCBockVpZ2h0aWVzVGFibGUuaHINCkZST00gKFNFTEVDVCB5ZWFySUQsIHBsYXllcklELCB0ZWFtSUQsIGhyIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPiAxOTc5IEFORCB5ZWFySUQgPCAxOTkwKSBockVpZ2h0aWVzVGFibGUNCkpPSU4gKFNFTEVDVCBNQVgoaHJFaWdodGllcy5ocikgYXMgbWF4X2hyLCB5ZWFySUQNCiAgICAgIEZST00gKFNFTEVDVCB5ZWFySUQsIHBsYXllcklELCBociBGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEID4gMTk3OSBBTkQgeWVhcklEIDwgMTk5MCkgaHJFaWdodGllcw0KICAgICAgR1JPVVAgQlkgeWVhcklEKSBockVpZ2h0aWVzVGFibGVNYXgNCk9OIGhyRWlnaHRpZXNUYWJsZS55ZWFySUQgPSBockVpZ2h0aWVzVGFibGVNYXgueWVhcklEIEFORCBockVpZ2h0aWVzVGFibGUuaHIgPSBockVpZ2h0aWVzVGFibGVNYXgubWF4X2hyDQpgYGANCg0KV2hhdCBhYm91dCBjYXRlZ29yaXppbmcgdGhlbSBieSBsZWFndWVzPyBXZSBjYW4gZG8gaXQgYnkgdGhyZWUgc21hbGwgbW9kaWZpY2F0aW9ucyB0byB0aGUgcHJldmlvdXMgcXVlcnkuIEZpcnN0LCBmb3IgZWFjaCBvZiB0aGUgaW5uZXIgYFNFTEVDVGAsIHdlIHJldHVybiB0aGUgbGdJRCBjb2x1bW4sIGkuZS4sIEFMIG9yIE5MLiBTZWNvbmQsIGluIHRoZSB0YWJsZSB3aGVyZSB3ZSBkbyB0aGUgZ3JvdXBpbmcsIHdlIGdyb3VwIGJ5IGxlYWd1ZSwgdGhlbiBieSB5ZWFyOiBgR1JPVVAgQlkgbGdJRCwgeWVhcklEYC4gVGhpcmQsIG9uIHRoZSBgSk9JTmAsIHdlIGpvaW4gdGhlIHR3byB0YWJsZXMgYnkgbGVhZ3VlIGluIGFkZGl0aW9uIHRvIGhvbWUgcnVucyBhbmQgeWVhci4NCmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQpTRUxFQ1QgaHJFaWdodGllc1RhYmxlLmxnSUQgYXMgbGVhZ3VlLCBockVpZ2h0aWVzVGFibGUueWVhcklEIGFzIHllYXIsIHBsYXllcklELCB0ZWFtSUQsIGhyRWlnaHRpZXNUYWJsZS5ocg0KRlJPTSAoU0VMRUNUIGxnSUQsIHllYXJJRCwgcGxheWVySUQsIHRlYW1JRCwgaHIgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA+IDE5NzkgQU5EIHllYXJJRCA8IDE5OTApIGhyRWlnaHRpZXNUYWJsZQ0KSk9JTiAoU0VMRUNUIE1BWChockVpZ2h0aWVzLmhyKSBhcyBtYXhfaHIsIGxnSUQsIHllYXJJRA0KICAgICAgRlJPTSAoU0VMRUNUIGxnSUQsIHllYXJJRCwgcGxheWVySUQsIGhyIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPiAxOTc5IEFORCB5ZWFySUQgPCAxOTkwKSBockVpZ2h0aWVzDQogICAgICBHUk9VUCBCWSBsZ0lELCB5ZWFySUQpIGhyRWlnaHRpZXNUYWJsZU1heA0KT04gaHJFaWdodGllc1RhYmxlLmxnSUQgPSBockVpZ2h0aWVzVGFibGVNYXgubGdJRCBBTkQgaHJFaWdodGllc1RhYmxlLnllYXJJRCA9IGhyRWlnaHRpZXNUYWJsZU1heC55ZWFySUQgQU5EIGhyRWlnaHRpZXNUYWJsZS5ociA9IGhyRWlnaHRpZXNUYWJsZU1heC5tYXhfaHINCk9SREVSIEJZIGhyRWlnaHRpZXNUYWJsZS55ZWFySUQsIGhyRWlnaHRpZXNUYWJsZS5sZ0lEDQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRifQ0KU0VMRUNUIGhyRWlnaHRpZXNUYWJsZS5sZ0lEIGFzIGxlYWd1ZSwgaHJFaWdodGllc1RhYmxlLnllYXJJRCBhcyB5ZWFyLCBwbGF5ZXJJRCwgdGVhbUlELCBockVpZ2h0aWVzVGFibGUuaHINCkZST00gKFNFTEVDVCBsZ0lELCB5ZWFySUQsIHBsYXllcklELCB0ZWFtSUQsIGhyIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQgPiAxOTc5IEFORCB5ZWFySUQgPCAxOTkwKSBockVpZ2h0aWVzVGFibGUNCkpPSU4gKFNFTEVDVCBNQVgoaHJFaWdodGllcy5ocikgYXMgbWF4X2hyLCBsZ0lELCB5ZWFySUQNCiAgICAgIEZST00gKFNFTEVDVCBsZ0lELCB5ZWFySUQsIHBsYXllcklELCBociBGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEID4gMTk3OSBBTkQgeWVhcklEIDwgMTk5MCkgaHJFaWdodGllcw0KICAgICAgR1JPVVAgQlkgbGdJRCwgeWVhcklEKSBockVpZ2h0aWVzVGFibGVNYXgNCk9OIGhyRWlnaHRpZXNUYWJsZS5sZ0lEID0gaHJFaWdodGllc1RhYmxlTWF4LmxnSUQgQU5EIGhyRWlnaHRpZXNUYWJsZS55ZWFySUQgPSBockVpZ2h0aWVzVGFibGVNYXgueWVhcklEIEFORCBockVpZ2h0aWVzVGFibGUuaHIgPSBockVpZ2h0aWVzVGFibGVNYXgubWF4X2hyDQpPUkRFUiBCWSBockVpZ2h0aWVzVGFibGUueWVhcklELCBockVpZ2h0aWVzVGFibGUubGdJRA0KYGBgDQo8YnI+DQoNCiMjIDMuMCBJbXBvcnRpbmcgZGF0YSBmcm9tIHRoZSBMYWhtYW4gU1FMIGRhdGFiYXNlIGludG8gUg0KV2UgY2FuIGltcG9ydCBkYXRhIGludG8gUiB0byBkbyB2aXN1YWxpemF0aW9ucy4gV2UgZG8gdGhpcyBieSBkZXNpZ25pbmcgYW5kIG1hbnVmYWN0dXJpbmcgYSB0YWJsZSBpbiBTUUwgZmlyc3QsIHRoZW4gaW1wb3J0aW5nIGl0IGFzIGEgZGF0YSBmcmFtZSBpbnRvIFIuDQoNCiMjIyAzLjEgSG9tZSBydW5zIGJ5IGJhdHRpbmcgcHJlZmVyZW5jZQ0KSSB3YW50IHRvIHBsb3QgdGhlIGRpc3RyaWJ1dGlvbiBvZiBob21lIHJ1bnMgaW4gMTk4MCBieSBiYXR0aW5nIHByZWZlcmVuY2UsIGxlZnQgb3IgcmlnaHQuIFdlIGZpcnN0IGJ1aWxkIHRoZSBxdWVyeSB0byBtYW51ZmFjdHVyZSB0aGUgdGFibGUgdGhlIHdheSB3ZSB3YW50IGl0LCB0aGVuIHdlIGltcG9ydCB0aGUgdGFibGUgYXMgYSBkYXRhZnJhbWUgaW50byBSLiBXZSBjcmVhdGUgYSB0YWJsZSBieSBmaWx0ZXJpbmcgdGhlIEJhdHRpbmcgdGFibGUgdG8gaW5jbHVkZSBvbmx5IDE5ODAgZGF0YSwgdGhlbiBgSk9JTmAgaXQgd2l0aCB0aGUgTUFTVEVSIHRhYmxlIGBPTmAgcGxheWVySUQgdG8gZ2V0IHRoZSBiYXR0aW5nIHByZWZlcmVuY2UgZm9yIHRoYXQgcGxheWVyLiBJdCdzIHByZXR0eSBzdHJhaWdodGZvcndhcmQsIGJ1dCB3ZSBzdGlsbCB3ZSBuZWVkIHRvIGBHUk9VUCBCWWAgdGhlIEJhdHRpbmcgdGFibGUgcmVzdWx0cyBieSBob21lIHJ1biB0b3RhbHMsIHBlciBwbGF5ZXIsIHRvIGFjY291bnQgZm9yIHBsYXllcnMgdGhhdCBwbGF5ZWQgZm9yIG1vcmUgdGhhbiBvbmUgdGVhbSBpbiAxOTgwLiBGb3IgZXhhbXBsZSwgSmFzb24gVGhvbXBzb24gcGxheWVkIGZvciB0d28gdGVhbXMgaW4gMTk4MCwgdGhlIERldHJvaXQgVGlnZXJzIGFuZCB0aGUgQ2FsaWZvcm5pYSBBbmdlbHM6DQpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KU0VMRUNUIHBsYXllcklELCB0ZWFtSUQsIGhyLCBHDQpGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEPTE5ODAgQU5EIHBsYXllcklEID0gInRob21wamEwMSINCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJ9DQpTRUxFQ1QgcGxheWVySUQsIHRlYW1JRCwgaHIsIEcNCkZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQ9MTk4MCBBTkQgcGxheWVySUQgPSAidGhvbXBqYTAxIg0KYGBgDQo8YnI+DQoNClNvIGhlIHNob3VsZCBjb3VudCBhcyBvbmUgbGVmdC1oYW5kZWQgLXBlciB0aGUgTUFTVEVSIHRhYmxlLSBiYXR0ZXIgd2l0aCAyMSBob21lIHJ1bnMgaW4gMTk4MC4NCg0KSGVyZSBpcyB0aGUgd2hvbGUgcXVlcnkuIFdlIGFyZSBmaWx0ZXJpbmcgZm9yIHBsYXllcnMgd2hvIHBhcnRpY2lwYXRlZCBpbiBhdCBsZWFzdCAxMDAgZ2FtZXMuIFRoaXMgaXMgYmVjYXVzZSBob21lIHJ1bnMgd2VyZSByYXJlIGVub3VnaCBpbiAxOTgwLCBldmVuIGZvciBwbGF5ZXJzIHRoYXQgcGFydGljaXBhdGVkIGluIGV2ZXJ5IGdhbWUuIElmIHdlIGluY2x1ZGUgcGxheWVycyB0aGF0IHdlcmUgdXNlZCBzcGFyaW5nbHksIHdlIHdvdWxkIGdldCAqKmEgbG90Kiogb2YgemVybydzLg0KYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NClNFTEVDVCBiMTk4MC5ocl9zdW0gQVMgaHIsIE1BU1RFUi5iYXRzDQpGUk9NIChTRUxFQ1QgcGxheWVySUQsIHN1bShocikgYXMgaHJfc3VtDQogICAgICBGUk9NIEJhdHRpbmcNCiAgICAgIFdIRVJFIHllYXJJRCA9IDE5ODAgQU5EIEcgPiA5OQ0KICAgICAgR1JPVVAgQlkgcGxheWVySUQpIGIxOTgwDQpKT0lOIE1BU1RFUg0KT04gYjE5ODAucGxheWVySUQgPSBNQVNURVIucGxheWVySUQNCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJ9DQpTRUxFQ1QgYjE5ODAuaHJfc3VtIEFTIGhyLCBNQVNURVIuYmF0cw0KRlJPTSAoU0VMRUNUIHBsYXllcklELCBzdW0oaHIpIGFzIGhyX3N1bQ0KICAgICAgRlJPTSBCYXR0aW5nDQogICAgICBXSEVSRSB5ZWFySUQgPSAxOTgwIEFORCBHID4gOTkNCiAgICAgIEdST1VQIEJZIHBsYXllcklEKSBiMTk4MA0KSk9JTiBNQVNURVINCk9OIGIxOTgwLnBsYXllcklEID0gTUFTVEVSLnBsYXllcklEDQpgYGANCjxicj4NCg0KV2UgdXNlIHRoZSBmdW5jdGlvbiBgZGJHZXRRdWVyeSgpYCB0byBnZXQgYnJpbmcgdGhlIG1hbnVmYWN0dXJlZCB0YWJsZSBhcyBhIGRhdGFmcmFtZSBpbnRvIFI6DQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmJhdFByZWYxOTgwIDwtIGRiR2V0UXVlcnkoZGIsIlNFTEVDVCBiMTk4MC5ocl9zdW0gQVMgaHIsIE1BU1RFUi5iYXRzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NIChTRUxFQ1QgcGxheWVySUQsIHN1bShocikgYXMgaHJfc3VtDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NIEJhdHRpbmcNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFIHllYXJJRCA9IDE5ODAgQU5EIEcgPiA5OQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgcGxheWVySUQpIGIxOTgwDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBKT0lOIE1BU1RFUg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT04gYjE5ODAucGxheWVySUQgPSBNQVNURVIucGxheWVySUQiKQ0KYmF0UHJlZjE5ODAkYmF0cyA8LSBhcy5mYWN0b3IoYmF0UHJlZjE5ODAkYmF0cykNCnN1bW1hcnkoYmF0UHJlZjE5ODApDQpgYGANCjxicj4NCg0KVGhlbiB3ZSBjYW4gcGxvdCB0aGUgaG9tZSBydW4gZGlzdHJpYnV0aW9ucyBieSBiYXR0aW5nIHByZWZlcmVuY2UuIFdlIHdpbGwgdXNlIHRoZSByQm9rZWggbGlicmFyeSwgd2hpY2ggcmVuZGVycyBwbG90cyB3aXRoIHBhbiBhbmQgem9vbSBjYXBhYmlsaXRpZXMuDQpgYGB7cn0NCmxpYnJhcnkocmJva2VoKQ0KZmlndXJlKHRpdGxlID0gIkhvbWUgcnVucyBoaXQgdnMgYmF0dGluZyBwcmVmZXJlbmNlIGluIDE5ODAiLCB3aWR0aCA9IDYwMCwgeGxhYiA9ICJCYXR0aW5nIHByZWZlcmVuY2UiLCB5bGFiID0gIkhvbWUgcnVucyIpICU+JSAgbHlfYm94cGxvdCh4PWJhdHMsIHk9aHIsIGRhdGEgPSBiYXRQcmVmMTk4MCwgZmlsbF9jb2xvciA9ICIjNTZCNEU5IiwgbGluZV9jb2xvciA9ICJibGFjayIsIGZpbGxfYWxwaGE9MSwgd2lkdGggPSAwLjQpDQpgYGANCjxicj4NCg0KV2hvYSwgMzIgYW1iaWRleHRyb3VzIGJhdHRlcnMgd2hvIHNhdyBhIGxvdCBvZiBhY3Rpb24gaW4gMTk4MCEgT25lIG9mIHRoZW0gaGl0IG1vcmUgdGhhbiAzMCBob21lIHJ1bnMsIHdoZW4gMzAgaG9tZSBydW5zIHdhcyBzdGlsbCBjb25zaWRlcmVkIG5ld3N3b3J0aHkuIFdobyB3YXMgdGhhdD8NCmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQpTRUxFQ1QgQ09OQ0FUKG5hbWVGaXJzdCwgIiAiLCBuYW1lTGFzdCkgQVMgZnVsbE5hbWUsIGJhdHMNCkZST00gKFNFTEVDVCBwbGF5ZXJJRCBGUk9NIEJhdHRpbmcgV0hFUkUgeWVhcklEID0gMTk4MCBBTkQgaHIgPiAzMCkgc3R1ZHMxOTgwDQpKT0lOIE1BU1RFUiBPTiBNQVNURVIucGxheWVySUQgPSBzdHVkczE5ODAucGxheWVySUQNCldIRVJFIE1BU1RFUi5iYXRzID0gIkIiDQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRifQ0KU0VMRUNUIENPTkNBVChuYW1lRmlyc3QsICIgIiwgbmFtZUxhc3QpIEFTIGZ1bGxOYW1lLCBiYXRzDQpGUk9NIChTRUxFQ1QgcGxheWVySUQgRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRCA9IDE5ODAgQU5EIGhyID4gMzApIHN0dWRzMTk4MA0KSk9JTiBNQVNURVIgT04gTUFTVEVSLnBsYXllcklEID0gc3R1ZHMxOTgwLnBsYXllcklEDQpXSEVSRSBNQVNURVIuYmF0cyA9ICJCIg0KYGBgDQoNCkl0IHdhcyBmdXR1cmUgSGFsbCBvZiBGYW1lciBbRWRkaWUgTXVycmF5XShodHRwOi8vYmFzZWJhbGxoYWxsLm9yZy9ob2YvbXVycmF5LWVkZGllKSENCg0KIVtdKEVkZGllX011cnJheV9iYXNlYmFsbF9jYXJkLkpQRyAiRWRkaWUgTXVycmF5IikNCg0KIyMjIDMuMiBUZWFtIGF0dGVuZGFuY2UgYnkgbGVhZ3VlIGFuZCBkaXZpc2lvbg0KV2Ugd2FudCB0byB2aXN1YWxpemUgYmFsbHBhcmsgYXR0ZW5kYW5jZSBpbiAxOTgwLiBJbiB0aGUgTGFobWFuIGRhdGFiYXNlLCB0aGUgYXR0ZW5kYW5jZSBpcyBrZXB0IGluIHRoZSBUZWFtcyB0YWJsZS4gQSBzaW1wbGUgcXVlcnkgcmV0dXJucyB0aGUgaW5mbyB3ZSB3YW50Lg0KYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NClNFTEVDVCBuYW1lIEFTIHRlYW0sIGF0dGVuZGFuY2UsIGxnSUQgYXMgbGVhZ3VlLCBkaXZJRCBBUyBkaXZpc2lvbiBGUk9NIFRlYW1zIFdIRVJFIHllYXJJRCA9IDE5ODANCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJ9DQpTRUxFQ1QgbmFtZSBBUyB0ZWFtLCBhdHRlbmRhbmNlLCBsZ0lEIGFzIGxlYWd1ZSwgZGl2SUQgQVMgZGl2aXNpb24gRlJPTSBUZWFtcyBXSEVSRSB5ZWFySUQgPSAxOTgwDQpgYGANCjxicj4NCg0KTm93IHdlIGNhbiBlbWJlZCB0aGF0IHF1ZXJ5IGludG8gYGRiR2V0UXVlcnkoKWAgdG8gYnJpbmcgdGhlIHJlc3VsdHMgaW50byBSLg0KYGBge3J9DQphdHRlbmRhbmNlXzE5ODAgPC0gZGJHZXRRdWVyeShkYiwgIlNFTEVDVCBuYW1lIEFTIHRlYW0sIGF0dGVuZGFuY2UsIGxnSUQgYXMgbGVhZ3VlLCBkaXZJRCBBUyBkaXZpc2lvbiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSBUZWFtcyBXSEVSRSB5ZWFySUQgPSAxOTgwIikNCiMgQ2hhbmdpbmcgYXR0ZW5kYW5jZSwgd2hpY2ggaXMgcmVhZCBhcyBhIHN0cmluZywgdG8gbnVtZXJpYyANCmF0dGVuZGFuY2VfMTk4MCRhdHRlbmRhbmNlIDwtIGFzLm51bWVyaWMoYXR0ZW5kYW5jZV8xOTgwJGF0dGVuZGFuY2UpDQojIENoYW5naW5nIHRoZSAiRSIgYW5kICJXIiBpbiBkaXZpc2lvbiB0byAiRWFzdCIgYW5kICJXZXN0Ig0KYXR0ZW5kYW5jZV8xOTgwJGRpdmlzaW9uW2F0dGVuZGFuY2VfMTk4MCRkaXZpc2lvbiA9PSAiRSJdIDwtICJFYXN0Ig0KYXR0ZW5kYW5jZV8xOTgwJGRpdmlzaW9uW2F0dGVuZGFuY2VfMTk4MCRkaXZpc2lvbiA9PSAiVyJdIDwtICJXZXN0Ig0KIyBDcmVhdGluZyBhICJsZWFndWVfZGl2aXNpb24iIGNvbHVtbg0KYXR0ZW5kYW5jZV8xOTgwJGxlYWd1ZV9kaXZpc2lvbiA8LSBwYXN0ZShhdHRlbmRhbmNlXzE5ODAkbGVhZ3VlLCBhdHRlbmRhbmNlXzE5ODAkZGl2aXNpb24pDQpzdW1tYXJ5KGF0dGVuZGFuY2VfMTk4MCkNCmBgYA0KPGJyPg0KDQpUaGVuIHdlIGNhbiBjcmVhdGUgdGhlIGJveHBsb3QuDQpgYGB7cn0NCmZpZ3VyZSh3aWR0aD02MDAsIHRpdGxlID0gIkJhbGxwYXJrIGF0dGVuZGFuY2UgaW4gMTk4MCIsIHhsYWIgPSAiTGVhZ3VlIGRpdmlzaW9uIiwgeWxhYiA9ICJCYWxscGFyayBhdHRlbmRhbmNlIikgJT4lIGx5X2JveHBsb3QoeCA9IGxlYWd1ZV9kaXZpc2lvbiwgeSA9IGF0dGVuZGFuY2UsIGRhdGEgPSBhdHRlbmRhbmNlXzE5ODAsIGZpbGxfY29sb3IgPSAiIzU2QjRFOSIsIGxpbmVfY29sb3IgPSAiYmxhY2siLCBmaWxsX2FscGhhPTEsIHdpZHRoID0gMC40KSAlPiUgeV9heGlzKG51bWJlcl9mb3JtYXR0ZXIgPSAibnVtZXJhbCIpDQpgYGANCjxicj4NCg0KV2UgY2FuIGFsc28gdmlzdWFsaXplIHRoZSBhdHRlbmRhbmNlIHVzaW5nIGEgdHJlZSBtYXAuDQpgYGB7cn0NCmxpYnJhcnkodHJlZW1hcCkNCnRyZWVtYXAoYXR0ZW5kYW5jZV8xOTgwLCBpbmRleD1jKCJsZWFndWVfZGl2aXNpb24iLCAidGVhbSIpLCB2U2l6ZSA9ICJhdHRlbmRhbmNlIiwgcGFsZXR0ZSA9IGMoIiNFNjlGMDAiLCAiIzU2QjRFOSIsICIjMDA5RTczIiwgIiNDQzc5QTciKSwgdGl0bGUgPSAiQmFsbHBhcmsgYXR0ZW5kYW5jZSBieSBsZWFndWUgZGl2aXNpb24iLCB0aXRsZS5sZWdlbmQgPSAiTGVhZ3VlIGRpdmlzaW9uIiwgcG9zaXRpb24ubGVnZW5kID0gImJvdHRvbSIpDQpgYGANCjxicj4NCg0KQW1vbmcgb3RoZXIgdGhpbmdzLCB0aGUgcGxvdCBzaG93cyB0aGUgTG9zIEFuZ2VsZXMgRG9kZ2VycyBoYWQganVzdCBhYm91dCBhcyBtdWNoIGF0dGVuZGFuY2UgYXMgdGhyZWUgb3RoZXIgdGVhbXMgaW4gdGhlIE5MIFdlc3QgY29tYmluZWQ6IHRoZSBTYW4gRGllZ28gUGFkcmVzLCB0aGUgQXRsYW50YSBCcmF2ZXMsIGFuZCB0aGUgU2FuIEZyYW5jaXNjbyBHaWFudHMuIEFsdGhvdWdoIHRoZSBEb2RnZXJzIHdlcmUgdGhlIG9ubHkgTUxCIHRlYW0gdG8gdG9wIDMgbWlsbGlvbiBmYW5zIGluIGF0dGVuZGFuY2UgdGhhdCB5ZWFyLCB0aGV5IGZpbmlzaGVkIHRoZSBzZWFzb24gc2Vjb25kIGluIHRoZSBOTCBXZXN0LCBvbmUgZ2FtZSBiZWhpbmQgdGhlIEhvdXN0b24gQXN0cm9zLg0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGIsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpTRUxFQ1QgYi5wbGF5ZXJJRCwgYi50ZWFtSUQsIGIuaHIgRlJPTSAoU0VMRUNUICogRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRD0xOTgwIEFORCBHID4gNTApIEFTIGINCkxFRlQgSk9JTiAoU0VMRUNUICogRlJPTSBCYXR0aW5nIFdIRVJFIHllYXJJRD0xOTgwIEFORCBHID4gNTApIEFTIGIyDQpPTiBiLnRlYW1JRCA9IGIyLnRlYW1JRCBBTkQgYi5ociA8PSBiMi5ocg0KR1JPVVAgQlkgYi5wbGF5ZXJJRA0KSEFWSU5HIENPVU5UKCopIDw9IDINCk9SREVSIEJZIHRlYW1JRCwgYi5IUiBERVNDDQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRiLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KU0VMRUNUIGIucGxheWVySUQsIGIudGVhbUlELCBiLmhyIEZST00gKFNFTEVDVCAqIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQ9MTk4MCBBTkQgdGVhbUlEPSJOWU4iKSBBUyBiDQpMRUZUIEpPSU4gKFNFTEVDVCAqIEZST00gQmF0dGluZyBXSEVSRSB5ZWFySUQ9MTk4MCBBTkQgdGVhbUlEPSJOWU4iKSBBUyBiMg0KT04gYi50ZWFtSUQgPSBiMi50ZWFtSUQgQU5EIGIuaHIgPD0gYjIuaHINCkdST1VQIEJZIGIucGxheWVySUQNCkhBVklORyBDT1VOVCgqKSA8PSAyDQpPUkRFUiBCWSB0ZWFtSUQsIGIuSFIgREVTQw0KYGBgDQoNCmBgYHtzcWwgY29ubmVjdGlvbj1kYiwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NClNFTEVDVCBwbGF5ZXJJRCwgeWVhcklELCB0ZWFtSUQsIEcsIGhyIEZST00gQmF0dGluZyBXSEVSRSBwbGF5ZXJJRCA9ICJ3YXNoaWNsMDEiIEFORCB5ZWFySUQgPSAxOTgwDQpgYGANCjxicj4NCg0KIyMjIFJlZmVyZW5jZXM6DQoNCjEuIEFuZHJlcywgQW5keS4gKioqU2FiZXJtZXRyaWNzIDEwMTogSW50cm9kdWN0aW9uIHRvIEJhc2ViYWxsIEFuYWx5dGljcyoqKiwgU3VtbWVyIDIwMTQuIGVkWA0KDQoyLiBCZWF1bGlldSwgQWxhbi4gKioqTGVhcm5pbmcgU1FMKioqLiBTZWJhc3RvcG9sOiBPJ1JlaWxseSBNZWRpYSwgMjAwOS4gUERGDQoNCjMuIEFkbGVyLCBKb3NlcGguICoqKlIgaW4gYSBOdXRzaGVsbCwgU2Vjb25kIEVkaXRpb24qKiouIFNlYmFzdG9wb2w6IE8nUmVpbGx5IE1lZGlhLCAyMDEyLiBQREYuDQoNCjQuIEVyaWN0b24gYW5kIEpvaG4gV29vLiAqKipIb3cgdG8gc2VsZWN0IHByb2R1Y3QgdGhhdCBoYXZlIHRoZSBtYXhpbXVtIHByaWNlIG9mIGVhY2ggY2F0ZWdvcnk/KioqIFJldHJpZXZlZCBmcm9tIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTIzNjYzOTAvaG93LXRvLXNlbGVjdC1wcm9kdWN0LXRoYXQtaGF2ZS10aGUtbWF4aW11bS1wcmljZS1vZi1lYWNoLWNhdGVnb3J5DQoNCjUuIERpcmsgRWRkZXJidWV0dGVsIGFuZCBEYXZpZCBKYW1lcy4gKioqW1JdIGNvbm5lY3RpbmcgW2xvZ2dpbmddIFJNeVNRTCB0byBhbiBleHRlcm5hbCBzZXJ2ZXIgLSBTT0xWRUQqKiogUmV0cmlldmVkIGZyb20gaHR0cHM6Ly9zdGF0LmV0aHouY2gvcGlwZXJtYWlsL3ItaGVscC8yMDA3LURlY2VtYmVyLzE0ODg0MC5odG1sDQoNCjYuIFRoZSBUcmFkaW5nIENhcmQgRGF0YWJhc2UuICoqKjE5ODEgVG9wcHMgY2FyZHMqKiouIFJldHJpZXZlZCBmcm9tIGh0dHA6Ly93d3cudHJhZGluZ2NhcmRkYi5jb20vVmlld1NldC5jZm0vc2lkLzg1LzE5ODEtVG9wcHMuDQo=