R for Data Science, Chapter 5

Library functions

library(rmarkdown)
library(knitr)
library(ggplot2)
library(tidyverse)

library(nycflights13)

5.2.4 Exercises

Okay, let’s start up looking at the data frame itself!

nycflights13::flights
flights <- nycflights13::flights

Okay, so now let us move on to the flitering!

1. Find all flights that

a. Had an arrival delay of two or more hours

Okay, for this one we just follow the filter function brought forward in 5.2. One thing to note, the arr_delay is listed in minutes so two or more hours should be entered as 120 minutes.

filter(flights, arr_delay >= 120)

b. Flew to Houston (IAH or HOU)

There are two options for this question, you can either do dest == or you can use pipping (%in%)

filter(flights, dest == "IAH" | dest == "HOU")

filter(flights, dest %in% c ("IAH", "HOU"))

c. Were operated by United, American, or Delta

First thing I’m going to do is to see the various airline carriers to see what the different initials are.

unique(flights$carrier)
 [1] "UA" "AA" "B6" "DL" "EV" "MQ" "US" "WN" "VX" "FL" "AS" "9E" "F9" "HA" "YV" "OO"
airlines

It looks like I’m going to go for UA, AA, DL

filter (flights, carrier %in% c ("UA", "AA", "DL"))

d. Departed in summer (July, August, and September)

filter (flights, month %in% c ("July", "August", "September"))

The reason that did not work is that the months have a numerical value assigned to them! There is also a lot of different ways to approach this question, below is one option.

filter (flights, month %in% c (7, 8, 9))

For this I went with c, but I just as easily could have done 7:9. Because it is numerical, you can also use the strategy we did for question 1a.

filter (flights, month >= 7, month <= 9)

One way to confirm that the three months were all selected is to do a summary of this filter.

months.flights <- filter (flights, month >= 7, month <= 9)

summary(months.flights)
      year          month            day           dep_time    sched_dep_time   dep_delay          arr_time    sched_arr_time   arr_delay     
 Min.   :2013   Min.   :7.000   Min.   : 1.00   Min.   :   1   Min.   : 106   Min.   : -26.00   Min.   :   1   Min.   :   1   Min.   : -68.0  
 1st Qu.:2013   1st Qu.:7.000   1st Qu.: 8.00   1st Qu.: 904   1st Qu.: 905   1st Qu.:  -5.00   1st Qu.:1051   1st Qu.:1115   1st Qu.: -19.0  
 Median :2013   Median :8.000   Median :16.00   Median :1356   Median :1359   Median :  -1.00   Median :1523   Median :1550   Median :  -7.0  
 Mean   :2013   Mean   :7.979   Mean   :15.88   Mean   :1346   Mean   :1342   Mean   :  13.79   Mean   :1485   Mean   :1525   Mean   :   6.4  
 3rd Qu.:2013   3rd Qu.:9.000   3rd Qu.:23.00   3rd Qu.:1743   3rd Qu.:1729   3rd Qu.:  11.00   3rd Qu.:1931   3rd Qu.:1938   3rd Qu.:  13.0  
 Max.   :2013   Max.   :9.000   Max.   :31.00   Max.   :2400   Max.   :2359   Max.   :1014.00   Max.   :2400   Max.   :2359   Max.   :1007.0  
                                                NA's   :1878                  NA's   :1878      NA's   :2053                  NA's   :2267    
   carrier              flight       tailnum             origin              dest              air_time        distance         hour           minute    
 Length:86326       Min.   :   1   Length:86326       Length:86326       Length:86326       Min.   : 21.0   Min.   :  17   Min.   : 1.00   Min.   : 0.0  
 Class :character   1st Qu.: 583   Class :character   Class :character   Class :character   1st Qu.: 79.0   1st Qu.: 502   1st Qu.: 9.00   1st Qu.:10.0  
 Mode  :character   Median :1543   Mode  :character   Mode  :character   Mode  :character   Median :122.0   Median : 833   Median :13.00   Median :29.0  
                    Mean   :1981                                                            Mean   :146.2   Mean   :1054   Mean   :13.16   Mean   :26.8  
                    3rd Qu.:3395                                                            3rd Qu.:187.0   3rd Qu.:1400   3rd Qu.:17.00   3rd Qu.:45.0  
                    Max.   :6181                                                            Max.   :640.0   Max.   :4983   Max.   :23.00   Max.   :59.0  
                                                                                            NA's   :2267                                                 
   time_hour                  
 Min.   :2013-07-01 05:00:00  
 1st Qu.:2013-07-23 19:00:00  
 Median :2013-08-15 09:00:00  
 Mean   :2013-08-15 18:22:37  
 3rd Qu.:2013-09-07 16:00:00  
 Max.   :2013-09-30 23:00:00  
                              

e. Arrived more than two hours late, but didn’t leave late

filter (flights, arr_delay > 120, dep_delay == 0)

This is good, if you don’t look at the rest of the data and see that there are some departures that leave even before “on time.” Which just sounds annoying as a passenger.

unique(flights$dep_delay)
  [1]    2    4   -1   -6   -4   -5   -3   -2    0    1   -8    8   11    3   13   24   -7   -9    9   47   39  -10    5  101    7   71  -11  853    6   43
 [31]   23   59   12   14   15   21   25   29  -15  -13   32  144   10   34   16   18  134   96   30   41   55   37   26   77   22   40   57   70   56   35
 [61]   31  115   38   50   27  105  122   88   64  119   54   84   33   42   52   82   36  -14   91   62  103   74  290  260   61   63  131   19   46  129
 [91]  155  157  216   73  121  109   51   72  255   49  285  -12  141  192   83  116  379   NA  156   20   80   79  107   45  179   75   28  104   17  100
[121]   65  120  224   90  268  334   67  139   69   99  128  337   76   98  133   85  181   53   66  102   97   48  168  180  164  158  140  175  108  125
[151]  185   68  111   93   44  126  162  174   58   86  171   81  123  252   60  106   78  291  177  137  -17  110  118  114   89  145  208  288  -19  142
[181]  203  127   95  257   94  327  225  -16  117  163  202  151  152   87  293  112  178  366  188  148  143 1301  253 1126  196  385  307  167  360  -30
[211]  -18  241  221  -22  282  -20  213  315  153  135  138  599  149  176   92  195  154  113  183  220  172  229  186  193  266  246  170  124  502  204
[241]  212  214  207  231  187  130  308  281  227  146  205  132  222  242  259  238  173  292  147  275  189  -21  161  276  251  198  150  271  256  274
[271]  159  190  165  233  160  199  239  194  166  184  478  191  210  209  318  169  329  262  230  336  323  294  206  254  270  328  197  182  287  349
[301]  211  136  295  201  280  -27  217  235  265  250  237  234  248  228  245  243  240  279  306  232  218  219  278  342  378  223  364  226  247  200
[331]  272  324  352  286  317  702  297  316  289  390  387  373  -25  215  310  -23  311  322  798  413  -32  335  367  299  305  277  398  351  339  341
[361]  347  636  298  312  302  408  313  687  303  244  896  283  309  300  389  333  405  361  431  301  382  330  261  548  340  273  249  374  -43  321
[391]  264  368  263  236  825  660  284  392  503  845  432  849  356  296  486  314  420  -33  269  415  319  355  320  592  747  788  786  404  354  -24
[421]  430  470  332  258  376  346  348  393  394  383  406  911  359  371  331  800  443  345  326  545  384  325  440  437  639  960  510  414  350  267
[451]  427  761  797  753  812  381  357  423  375  434  878  397  391  504  471  533  494  369  401  475  410  466  386  613  419  380  446  388  343  447
[481] 1137  467  426  790  787  803  899  436  396  500  454  411  363  353  589  452  304  629  653  399  362  453  479  634  576  409  580  483  365 1005
[511]  898  536  370  344  372  520  -26  508  338  424  696  473  514  358  602  593 1014  422
filter (flights, arr_delay > 120, dep_delay <= 0)

f. Were delayed by at least an hour, but made up over 30 minutes in flight

There is no explicit category for making up time in the flight. However, if you take the departure delay you can compare it with the arrival delay. If time was made up on the flight, than you would have a difference between the two numbers.

filter (flights, dep_delay >= 60, dep_delay - arr_delay > 30)

g. Departed between midnight and 6am (inclusive)

summary (flights$dep_time)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
      1     907    1401    1349    1744    2400    8255 

This summary, alongside the tables throughout this prompt, indicates that the departure and arrival times are in four digits. The Max is at 2400 (midnight) and the min is at 1 (12:01am)

filter (flights, dep_time >0, dep_time <= 600)

2. Another useful dplyr filtering helper is between(). What does it do? Can you use it to simplify the code needed to answer the previous challenges?

You can look this up through the help function

?between

Between allows you to create a shortcut from many of the filter codes above, as between() is a "shortcut for x >= left & x <= right. It is used as between (x, left, right). This can replace just about any of the answers to the questions above, let’s look at question g since we just talked about it.

filter (flights, dep_time >0, dep_time <= 600)
filter (flights, between (dep_time, 0, 600))

3. How many flights have a missing dep_time? What other variables are missing? What might these rows represent?

filter (flights, is.na (dep_time))

There were 8,255 flights that are missing a departure time. Each of these 8,255 flights are also missing departure delays, arrival times, and arrival delays. What this indicates is that if one is missing, the other will be missing as well. Of course, that is a obvious observation. This all boils down to the possibility that these flights were canceled. If a plane didn’t depart, it wouldn’t arrive.

4. Why is NA ^ 0 not missing? Why is NA | TRUE not missing? Why is FALSE & NA not missing? Can you figure out the general rule? (NA * 0 is a tricky counterexample!)

NA ^ 0
[1] 1
NA | TRUE
[1] TRUE
NA & FALSE
[1] FALSE

NA ^ 0 comes out to 1 because this code equates to x to the 0 power, and anything that is raised to the 0 power = 1.

NA | TRUE is not missing and TRUE because it is looking at something that is not defined. Also, because it is not explicitly defining something anything could be true. True is True, nothing is True, False is True if something is false. No matter what the missing value is (true or false), this code means it will be true.

NA & False is not missing and FALSE for basically the same reason as above, but inverse. If you put anything next to FALSE (the &) it will always be false. Anything & False is ultimately FALSE. Not matter what the missing value is (true or false), this code means it will be false.

I could be completely wrong, but I believe that the general rule is that if something isn’t clearly defined it will equate to a general mathematical rule. It all comes down to the language assigned with the values? You ultimately need something to equal what the language is saying. NA | False would be a missing because ultimately TRUE | FALSE stile == TRUE.

5.3.1 Exercises

1. How could you use arrange() to sort all missing values to the start? (Hint: use is.na()).

arrange (flights, dep_time) %>%
  tail()

So, by just using arrange you are not sorting all of the missing values in their order at the start. They are inherently sorted at the end. In order to present the missing values to the start (and order so that January appears rather than September).

To mix that up, we take the hint from the question. But we do it alongside the re-ordering function (desc()) that is also described in the R for Data Science chapter 5.

arrange (flights, desc(is.na(dep_time)))

2a. Sort flights to find the most delayed flights.

This is a lot more straight forward. Just do what I did above, and forget about the is.na. We don’t care about those missing numbers, because we only care about those poor people who had their flights delayed MOST due to weather, mechanical issues, or geese over the Hudson. Because we want the hightest values, we use the descending order function.

arrange (flights, desc(dep_delay))

2b. Find the flights that left earliest.

Because we want the lowest numbers, we just ditch the desc.

arrange (flights, dep_delay)

This still baffles me. How can a flight leave early? I’d still be grabbing a cup of coffee from Dunkin.

3. Sort flights to find the fastest (highest speed) flights.

This kind of left we baffled for a bit, cause how do you define “fastest.” By looking at the rows we have already defined for us, I would say that air_time means the fastest? Cause we aren’t looking at hours or minutes, cause just because a flight was shorter doesn’t mean it is faster. Some people blow money to fly from BWI to Richmond, VA. That plane may take its time for all we know.

arrange (flights, air_time)

4a. Which flights traveled the farthest?

Just like above, you could interpret this question as being related to air time, but I decided to go with distance. Just to mix up what I was sorting.

arrange (flights, desc(distance))

4b. Which traveled the shortest?

arrange (flights, distance)

5.4.1 Exercises

1. Brainstorm as many ways as possible to select dep_time, dep_delay, arr_time, and arr_delay from flights.

Well, we can first do it the simple way. By name.

select(flights, dep_time, dep_delay, arr_time, arr_delay)

You can select the variables through their column numbers.

select (flights, 4, 6, 7, 9)

You can do starts_with ()

select (flights, starts_with("dep_"), starts_with ("arr"))

all (of) and any (of) -> both of which we will talk more about for question 3.

select (flights, all_of (c("dep_time", "dep_delay", "arr_time", "arr_delay")))
select (flights, any_of (c("dep_time", "dep_delay", "arr_time", "arr_delay")))

For other options, and they are almost “endless,” you can look at ?select. Plus, there are other ways of approaching this.

?select

2. What happens if you include the name of a variable multiple times in a select() call?

select (flights, year, month, day, dep_time, dep_time)

It looks like it just skips over the repeated varaible, since depature time was only displayed once.

3a. What does the any_of() function do?

?any_of

It allows you to select variable from character vectors, like that of all_of. What any_of does is look at variables contained in a character vector without checking for missing variables. Any_of is great for checking negative selections, as it will ignore anything out of the ‘sorts!’

3b. Why might it be helpful in conjunction with this vector?

vars <- c("year", "month", "day", "dep_delay", "arr_delay")
select(flights, any_of(vars))

It is useful because it can cut the chase of constantly having to retype out the variable names every time you apply them. By creating a vector you are able to streamline your data a bit for both ease and for being better consistent.

4a. Does the result of running the following code surprise you?

select(flights, contains("TIME"))

A bit? Looking more into the function afterwards, it makes plenty of sense. Everything in R is generally case sensitive, but contains ignores that. In the case of this code, it looks for anything in your data frame that contains “time.” No matter the case involved.

4b. How do the select helpers deal with case by default?

This is essentially in place to make sure that nothing is left out unintentionally. I believe it is just to make the user interface easier, and helps allivate any potential human error.

4c. How can you change that default?

select(flights, contains("TIME", ignore.case = FALSE))
LS0tDQp0aXRsZTogIlByb2JsZW0gU2V0IDciDQphdXRob3I6ICJDYW0gV2Fsa2VyIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRoZW1lOiBqb3VybmFsDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQojIFIgZm9yIERhdGEgU2NpZW5jZSwgQ2hhcHRlciA1DQoNCiMjIExpYnJhcnkgZnVuY3Rpb25zDQoNCmBgYHtyfQ0KbGlicmFyeShybWFya2Rvd24pDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCmxpYnJhcnkobnljZmxpZ2h0czEzKQ0KYGBgDQoNCiMjIDUuMi40IEV4ZXJjaXNlcw0KDQpPa2F5LCBsZXQncyBzdGFydCB1cCBsb29raW5nIGF0IHRoZSBkYXRhIGZyYW1lIGl0c2VsZiENCmBgYHtyfQ0KbnljZmxpZ2h0czEzOjpmbGlnaHRzDQpmbGlnaHRzIDwtIG55Y2ZsaWdodHMxMzo6ZmxpZ2h0cw0KDQpgYGANCg0KT2theSwgc28gbm93IGxldCB1cyBtb3ZlIG9uIHRvIHRoZSBmbGl0ZXJpbmchDQoNCioqMS4gRmluZCBhbGwgZmxpZ2h0cyB0aGF0KioNCg0KDQoqKmEuIEhhZCBhbiBhcnJpdmFsIGRlbGF5IG9mIHR3byBvciBtb3JlIGhvdXJzKioNCg0KT2theSwgZm9yIHRoaXMgb25lIHdlIGp1c3QgZm9sbG93IHRoZSBmaWx0ZXIgZnVuY3Rpb24gYnJvdWdodCBmb3J3YXJkIGluIDUuMi4gT25lIHRoaW5nIHRvIG5vdGUsIHRoZSBhcnJfZGVsYXkgaXMgbGlzdGVkIGluIG1pbnV0ZXMgc28gdHdvIG9yIG1vcmUgaG91cnMgc2hvdWxkIGJlIGVudGVyZWQgYXMgMTIwIG1pbnV0ZXMuIA0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgYXJyX2RlbGF5ID49IDEyMCkNCmBgYA0KDQoNCioqYi4gRmxldyB0byBIb3VzdG9uIChJQUggb3IgSE9VKSoqDQoNClRoZXJlIGFyZSB0d28gb3B0aW9ucyBmb3IgdGhpcyBxdWVzdGlvbiwgeW91IGNhbiBlaXRoZXIgZG8gZGVzdCA9PSBvciB5b3UgY2FuIHVzZSBwaXBwaW5nICglaW4lKQ0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgZGVzdCA9PSAiSUFIIiB8IGRlc3QgPT0gIkhPVSIpDQoNCmZpbHRlcihmbGlnaHRzLCBkZXN0ICVpbiUgYyAoIklBSCIsICJIT1UiKSkNCmBgYA0KDQoqKmMuIFdlcmUgb3BlcmF0ZWQgYnkgVW5pdGVkLCBBbWVyaWNhbiwgb3IgRGVsdGEqKg0KDQpGaXJzdCB0aGluZyBJJ20gZ29pbmcgdG8gZG8gaXMgdG8gc2VlIHRoZSB2YXJpb3VzIGFpcmxpbmUgY2FycmllcnMgdG8gc2VlIHdoYXQgdGhlIGRpZmZlcmVudCBpbml0aWFscyBhcmUuDQpgYGB7cn0NCnVuaXF1ZShmbGlnaHRzJGNhcnJpZXIpDQoNCmFpcmxpbmVzDQpgYGANCg0KSXQgbG9va3MgbGlrZSBJJ20gZ29pbmcgdG8gZ28gZm9yIFVBLCBBQSwgREwNCmBgYHtyfQ0KZmlsdGVyIChmbGlnaHRzLCBjYXJyaWVyICVpbiUgYyAoIlVBIiwgIkFBIiwgIkRMIikpDQpgYGANCg0KKipkLiBEZXBhcnRlZCBpbiBzdW1tZXIgKEp1bHksIEF1Z3VzdCwgYW5kIFNlcHRlbWJlcikqKg0KDQpgYGB7cn0NCmZpbHRlciAoZmxpZ2h0cywgbW9udGggJWluJSBjICgiSnVseSIsICJBdWd1c3QiLCAiU2VwdGVtYmVyIikpDQpgYGANCg0KVGhlIHJlYXNvbiB0aGF0IGRpZCBub3Qgd29yayBpcyB0aGF0IHRoZSBtb250aHMgaGF2ZSBhIG51bWVyaWNhbCB2YWx1ZSBhc3NpZ25lZCB0byB0aGVtISBUaGVyZSBpcyBhbHNvIGEgbG90IG9mIGRpZmZlcmVudCB3YXlzIHRvIGFwcHJvYWNoIHRoaXMgcXVlc3Rpb24sIGJlbG93IGlzIG9uZSBvcHRpb24uDQpgYGB7cn0NCmZpbHRlciAoZmxpZ2h0cywgbW9udGggJWluJSBjICg3LCA4LCA5KSkNCmBgYA0KDQpGb3IgdGhpcyBJIHdlbnQgd2l0aCBjLCBidXQgSSBqdXN0IGFzIGVhc2lseSBjb3VsZCBoYXZlIGRvbmUgNzo5LiBCZWNhdXNlIGl0IGlzIG51bWVyaWNhbCwgeW91IGNhbiBhbHNvIHVzZSB0aGUgc3RyYXRlZ3kgd2UgZGlkIGZvciBxdWVzdGlvbiAxYS4gDQpgYGB7cn0NCmZpbHRlciAoZmxpZ2h0cywgbW9udGggPj0gNywgbW9udGggPD0gOSkNCmBgYA0KDQpPbmUgd2F5IHRvIGNvbmZpcm0gdGhhdCB0aGUgdGhyZWUgbW9udGhzIHdlcmUgYWxsIHNlbGVjdGVkIGlzIHRvIGRvIGEgc3VtbWFyeSBvZiB0aGlzIGZpbHRlci4NCmBgYHtyfQ0KbW9udGhzLmZsaWdodHMgPC0gZmlsdGVyIChmbGlnaHRzLCBtb250aCA+PSA3LCBtb250aCA8PSA5KQ0KDQpzdW1tYXJ5KG1vbnRocy5mbGlnaHRzKQ0KYGBgDQoNCioqZS4gQXJyaXZlZCBtb3JlIHRoYW4gdHdvIGhvdXJzIGxhdGUsIGJ1dCBkaWRu4oCZdCBsZWF2ZSBsYXRlKioNCg0KYGBge3J9DQpmaWx0ZXIgKGZsaWdodHMsIGFycl9kZWxheSA+IDEyMCwgZGVwX2RlbGF5ID09IDApDQpgYGANCg0KVGhpcyBpcyBnb29kLCBpZiB5b3UgZG9uJ3QgbG9vayBhdCB0aGUgcmVzdCBvZiB0aGUgZGF0YSBhbmQgc2VlIHRoYXQgdGhlcmUgYXJlIHNvbWUgZGVwYXJ0dXJlcyB0aGF0IGxlYXZlIGV2ZW4gYmVmb3JlICJvbiB0aW1lLiIgV2hpY2gganVzdCBzb3VuZHMgYW5ub3lpbmcgYXMgYSBwYXNzZW5nZXIuIA0KYGBge3J9DQp1bmlxdWUoZmxpZ2h0cyRkZXBfZGVsYXkpDQoNCmZpbHRlciAoZmxpZ2h0cywgYXJyX2RlbGF5ID4gMTIwLCBkZXBfZGVsYXkgPD0gMCkNCmBgYA0KDQoqKmYuIFdlcmUgZGVsYXllZCBieSBhdCBsZWFzdCBhbiBob3VyLCBidXQgbWFkZSB1cCBvdmVyIDMwIG1pbnV0ZXMgaW4gZmxpZ2h0KioNCg0KVGhlcmUgaXMgbm8gZXhwbGljaXQgY2F0ZWdvcnkgZm9yIG1ha2luZyB1cCB0aW1lIGluIHRoZSBmbGlnaHQuIEhvd2V2ZXIsIGlmIHlvdSB0YWtlIHRoZSBkZXBhcnR1cmUgZGVsYXkgeW91IGNhbiBjb21wYXJlIGl0IHdpdGggdGhlIGFycml2YWwgZGVsYXkuIElmIHRpbWUgd2FzIG1hZGUgdXAgb24gdGhlIGZsaWdodCwgdGhhbiB5b3Ugd291bGQgaGF2ZSBhIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIG51bWJlcnMuIA0KYGBge3J9DQpmaWx0ZXIgKGZsaWdodHMsIGRlcF9kZWxheSA+PSA2MCwgZGVwX2RlbGF5IC0gYXJyX2RlbGF5ID4gMzApDQpgYGANCg0KKipnLiBEZXBhcnRlZCBiZXR3ZWVuIG1pZG5pZ2h0IGFuZCA2YW0gKGluY2x1c2l2ZSkqKg0KDQpgYGB7cn0NCnN1bW1hcnkgKGZsaWdodHMkZGVwX3RpbWUpDQpgYGANCg0KVGhpcyBzdW1tYXJ5LCBhbG9uZ3NpZGUgdGhlIHRhYmxlcyB0aHJvdWdob3V0IHRoaXMgcHJvbXB0LCBpbmRpY2F0ZXMgdGhhdCB0aGUgZGVwYXJ0dXJlIGFuZCBhcnJpdmFsIHRpbWVzIGFyZSBpbiBmb3VyIGRpZ2l0cy4gVGhlIE1heCBpcyBhdCAyNDAwIChtaWRuaWdodCkgYW5kIHRoZSBtaW4gaXMgYXQgMSAoMTI6MDFhbSkNCmBgYHtyfQ0KZmlsdGVyIChmbGlnaHRzLCBkZXBfdGltZSA+MCwgZGVwX3RpbWUgPD0gNjAwKQ0KYGBgDQoNCioqMi4gQW5vdGhlciB1c2VmdWwgZHBseXIgZmlsdGVyaW5nIGhlbHBlciBpcyBiZXR3ZWVuKCkuIFdoYXQgZG9lcyBpdCBkbz8gQ2FuIHlvdSB1c2UgaXQgdG8gc2ltcGxpZnkgdGhlIGNvZGUgbmVlZGVkIHRvIGFuc3dlciB0aGUgcHJldmlvdXMgY2hhbGxlbmdlcz8qKg0KDQpZb3UgY2FuIGxvb2sgdGhpcyB1cCB0aHJvdWdoIHRoZSBoZWxwIGZ1bmN0aW9uDQpgYGB7cn0NCj9iZXR3ZWVuDQpgYGANCg0KQmV0d2VlbiBhbGxvd3MgeW91IHRvIGNyZWF0ZSBhIHNob3J0Y3V0IGZyb20gbWFueSBvZiB0aGUgZmlsdGVyIGNvZGVzIGFib3ZlLCBhcyBiZXR3ZWVuKCkgaXMgYSAic2hvcnRjdXQgZm9yIHggPj0gbGVmdCAmIHggPD0gcmlnaHQuIEl0IGlzIHVzZWQgYXMgYmV0d2VlbiAoeCwgbGVmdCwgcmlnaHQpLiBUaGlzIGNhbiByZXBsYWNlIGp1c3QgYWJvdXQgYW55IG9mIHRoZSBhbnN3ZXJzIHRvIHRoZSBxdWVzdGlvbnMgYWJvdmUsIGxldCdzIGxvb2sgYXQgcXVlc3Rpb24gZyBzaW5jZSB3ZSBqdXN0IHRhbGtlZCBhYm91dCBpdC4gDQpgYGB7cn0NCmZpbHRlciAoZmxpZ2h0cywgZGVwX3RpbWUgPjAsIGRlcF90aW1lIDw9IDYwMCkNCmZpbHRlciAoZmxpZ2h0cywgYmV0d2VlbiAoZGVwX3RpbWUsIDAsIDYwMCkpDQpgYGANCg0KKiozLiBIb3cgbWFueSBmbGlnaHRzIGhhdmUgYSBtaXNzaW5nIGRlcF90aW1lPyBXaGF0IG90aGVyIHZhcmlhYmxlcyBhcmUgbWlzc2luZz8gV2hhdCBtaWdodCB0aGVzZSByb3dzIHJlcHJlc2VudD8qKg0KDQpgYGB7cn0NCmZpbHRlciAoZmxpZ2h0cywgaXMubmEgKGRlcF90aW1lKSkNCmBgYA0KDQpUaGVyZSB3ZXJlIDgsMjU1IGZsaWdodHMgdGhhdCBhcmUgbWlzc2luZyBhIGRlcGFydHVyZSB0aW1lLiBFYWNoIG9mIHRoZXNlIDgsMjU1IGZsaWdodHMgYXJlIGFsc28gbWlzc2luZyBkZXBhcnR1cmUgZGVsYXlzLCBhcnJpdmFsIHRpbWVzLCBhbmQgYXJyaXZhbCBkZWxheXMuIFdoYXQgdGhpcyBpbmRpY2F0ZXMgaXMgdGhhdCBpZiBvbmUgaXMgbWlzc2luZywgdGhlIG90aGVyIHdpbGwgYmUgbWlzc2luZyBhcyB3ZWxsLiBPZiBjb3Vyc2UsIHRoYXQgaXMgYSBvYnZpb3VzIG9ic2VydmF0aW9uLiBUaGlzIGFsbCBib2lscyBkb3duIHRvIHRoZSBwb3NzaWJpbGl0eSB0aGF0IHRoZXNlIGZsaWdodHMgd2VyZSBjYW5jZWxlZC4gSWYgYSBwbGFuZSBkaWRuJ3QgZGVwYXJ0LCBpdCB3b3VsZG4ndCBhcnJpdmUuIA0KDQoNCioqNC4gV2h5IGlzIE5BIF4gMCBub3QgbWlzc2luZz8gV2h5IGlzIE5BIHwgVFJVRSBub3QgbWlzc2luZz8gV2h5IGlzIEZBTFNFICYgTkEgbm90IG1pc3Npbmc/IENhbiB5b3UgZmlndXJlIG91dCB0aGUgZ2VuZXJhbCBydWxlPyAoTkEgKiAwIGlzIGEgdHJpY2t5IGNvdW50ZXJleGFtcGxlISkqKg0KDQpgYGB7cn0NCk5BIF4gMA0KDQpOQSB8IFRSVUUNCg0KTkEgJiBGQUxTRQ0KYGBgDQoNCg0KTkEgXiAwIGNvbWVzIG91dCB0byAxIGJlY2F1c2UgdGhpcyBjb2RlIGVxdWF0ZXMgdG8geCB0byB0aGUgMCBwb3dlciwgYW5kIGFueXRoaW5nIHRoYXQgaXMgcmFpc2VkIHRvIHRoZSAwIHBvd2VyID0gMS4gDQoNCk5BIHwgVFJVRSBpcyBub3QgbWlzc2luZyBhbmQgVFJVRSBiZWNhdXNlIGl0IGlzIGxvb2tpbmcgYXQgc29tZXRoaW5nIHRoYXQgaXMgbm90IGRlZmluZWQuIEFsc28sIGJlY2F1c2UgaXQgaXMgbm90IGV4cGxpY2l0bHkgZGVmaW5pbmcgc29tZXRoaW5nIGFueXRoaW5nIGNvdWxkIGJlIHRydWUuIFRydWUgaXMgVHJ1ZSwgbm90aGluZyBpcyBUcnVlLCBGYWxzZSBpcyBUcnVlIGlmIHNvbWV0aGluZyBpcyBmYWxzZS4gTm8gbWF0dGVyIHdoYXQgdGhlIG1pc3NpbmcgdmFsdWUgaXMgKHRydWUgb3IgZmFsc2UpLCB0aGlzIGNvZGUgbWVhbnMgaXQgd2lsbCBiZSB0cnVlLg0KDQpOQSAmIEZhbHNlIGlzIG5vdCBtaXNzaW5nIGFuZCBGQUxTRSBmb3IgYmFzaWNhbGx5IHRoZSBzYW1lIHJlYXNvbiBhcyBhYm92ZSwgYnV0IGludmVyc2UuIElmIHlvdSBwdXQgYW55dGhpbmcgbmV4dCB0byBGQUxTRSAodGhlICYpIGl0IHdpbGwgYWx3YXlzIGJlIGZhbHNlLiBBbnl0aGluZyAmIEZhbHNlIGlzIHVsdGltYXRlbHkgRkFMU0UuIE5vdCBtYXR0ZXIgd2hhdCB0aGUgbWlzc2luZyB2YWx1ZSBpcyAodHJ1ZSBvciBmYWxzZSksIHRoaXMgY29kZSBtZWFucyBpdCB3aWxsIGJlIGZhbHNlLiANCg0KSSBjb3VsZCBiZSBjb21wbGV0ZWx5IHdyb25nLCBidXQgSSBiZWxpZXZlIHRoYXQgdGhlIGdlbmVyYWwgcnVsZSBpcyB0aGF0IGlmIHNvbWV0aGluZyBpc24ndCBjbGVhcmx5IGRlZmluZWQgaXQgd2lsbCBlcXVhdGUgdG8gYSBnZW5lcmFsIG1hdGhlbWF0aWNhbCBydWxlLiBJdCBhbGwgY29tZXMgZG93biB0byB0aGUgbGFuZ3VhZ2UgYXNzaWduZWQgd2l0aCB0aGUgdmFsdWVzPyBZb3UgdWx0aW1hdGVseSBuZWVkIHNvbWV0aGluZyB0byBlcXVhbCB3aGF0IHRoZSBsYW5ndWFnZSBpcyBzYXlpbmcuIE5BIHwgRmFsc2Ugd291bGQgYmUgYSBtaXNzaW5nIGJlY2F1c2UgdWx0aW1hdGVseSBUUlVFIHwgRkFMU0Ugc3RpbGUgPT0gVFJVRS4gDQoNCiMjIDUuMy4xIEV4ZXJjaXNlcw0KDQoqKjEuIEhvdyBjb3VsZCB5b3UgdXNlIGFycmFuZ2UoKSB0byBzb3J0IGFsbCBtaXNzaW5nIHZhbHVlcyB0byB0aGUgc3RhcnQ/IChIaW50OiB1c2UgaXMubmEoKSkuKioNCg0KYGBge3J9DQphcnJhbmdlIChmbGlnaHRzLCBkZXBfdGltZSkgJT4lDQogIHRhaWwoKQ0KYGBgDQoNCg0KU28sIGJ5IGp1c3QgdXNpbmcgYXJyYW5nZSB5b3UgYXJlIG5vdCBzb3J0aW5nIGFsbCBvZiB0aGUgbWlzc2luZyB2YWx1ZXMgaW4gdGhlaXIgb3JkZXIgYXQgdGhlIHN0YXJ0LiBUaGV5IGFyZSBpbmhlcmVudGx5IHNvcnRlZCBhdCB0aGUgZW5kLiBJbiBvcmRlciB0byBwcmVzZW50IHRoZSBtaXNzaW5nIHZhbHVlcyB0byB0aGUgc3RhcnQgKGFuZCBvcmRlciBzbyB0aGF0IEphbnVhcnkgYXBwZWFycyByYXRoZXIgdGhhbiBTZXB0ZW1iZXIpLg0KDQpUbyBtaXggdGhhdCB1cCwgd2UgdGFrZSB0aGUgaGludCBmcm9tIHRoZSBxdWVzdGlvbi4gQnV0IHdlIGRvIGl0IGFsb25nc2lkZSB0aGUgcmUtb3JkZXJpbmcgZnVuY3Rpb24gKGRlc2MoKSkgdGhhdCBpcyBhbHNvIGRlc2NyaWJlZCBpbiB0aGUgUiBmb3IgRGF0YSBTY2llbmNlIGNoYXB0ZXIgNS4gDQpgYGB7cn0NCmFycmFuZ2UgKGZsaWdodHMsIGRlc2MoaXMubmEoZGVwX3RpbWUpKSkNCmBgYA0KDQoNCioqMmEuIFNvcnQgZmxpZ2h0cyB0byBmaW5kIHRoZSBtb3N0IGRlbGF5ZWQgZmxpZ2h0cy4qKg0KDQpUaGlzIGlzIGEgbG90IG1vcmUgc3RyYWlnaHQgZm9yd2FyZC4gSnVzdCBkbyB3aGF0IEkgZGlkIGFib3ZlLCBhbmQgZm9yZ2V0IGFib3V0IHRoZSBpcy5uYS4gV2UgZG9uJ3QgY2FyZSBhYm91dCB0aG9zZSBtaXNzaW5nIG51bWJlcnMsIGJlY2F1c2Ugd2Ugb25seSBjYXJlIGFib3V0IHRob3NlIHBvb3IgcGVvcGxlIHdobyBoYWQgdGhlaXIgZmxpZ2h0cyBkZWxheWVkIE1PU1QgZHVlIHRvIHdlYXRoZXIsIG1lY2hhbmljYWwgaXNzdWVzLCBvciBnZWVzZSBvdmVyIHRoZSBIdWRzb24uIEJlY2F1c2Ugd2Ugd2FudCB0aGUgaGlnaHRlc3QgdmFsdWVzLCB3ZSB1c2UgdGhlIGRlc2NlbmRpbmcgb3JkZXIgZnVuY3Rpb24uDQpgYGB7cn0NCmFycmFuZ2UgKGZsaWdodHMsIGRlc2MoZGVwX2RlbGF5KSkNCmBgYA0KDQoqKjJiLiBGaW5kIHRoZSBmbGlnaHRzIHRoYXQgbGVmdCBlYXJsaWVzdC4qKg0KDQpCZWNhdXNlIHdlIHdhbnQgdGhlIGxvd2VzdCBudW1iZXJzLCB3ZSBqdXN0IGRpdGNoIHRoZSBkZXNjLg0KYGBge3J9DQphcnJhbmdlIChmbGlnaHRzLCBkZXBfZGVsYXkpDQpgYGANCg0KVGhpcyBzdGlsbCBiYWZmbGVzIG1lLiBIb3cgY2FuIGEgZmxpZ2h0IGxlYXZlIGVhcmx5PyBJJ2Qgc3RpbGwgYmUgZ3JhYmJpbmcgYSBjdXAgb2YgY29mZmVlIGZyb20gRHVua2luLg0KDQoqKjMuIFNvcnQgZmxpZ2h0cyB0byBmaW5kIHRoZSBmYXN0ZXN0IChoaWdoZXN0IHNwZWVkKSBmbGlnaHRzLioqDQoNClRoaXMga2luZCBvZiBsZWZ0IHdlIGJhZmZsZWQgZm9yIGEgYml0LCBjYXVzZSBob3cgZG8geW91IGRlZmluZSAiZmFzdGVzdC4iIEJ5IGxvb2tpbmcgYXQgdGhlIHJvd3Mgd2UgaGF2ZSBhbHJlYWR5IGRlZmluZWQgZm9yIHVzLCBJIHdvdWxkIHNheSB0aGF0IGFpcl90aW1lIG1lYW5zIHRoZSBmYXN0ZXN0PyBDYXVzZSB3ZSBhcmVuJ3QgbG9va2luZyBhdCBob3VycyBvciBtaW51dGVzLCBjYXVzZSBqdXN0IGJlY2F1c2UgYSBmbGlnaHQgd2FzIHNob3J0ZXIgZG9lc24ndCBtZWFuIGl0IGlzIGZhc3Rlci4gU29tZSBwZW9wbGUgYmxvdyBtb25leSB0byBmbHkgZnJvbSBCV0kgdG8gUmljaG1vbmQsIFZBLiBUaGF0IHBsYW5lIG1heSB0YWtlIGl0cyB0aW1lIGZvciBhbGwgd2Uga25vdy4gDQpgYGB7cn0NCmFycmFuZ2UgKGZsaWdodHMsIGFpcl90aW1lKQ0KYGBgDQoNCioqNGEuIFdoaWNoIGZsaWdodHMgdHJhdmVsZWQgdGhlIGZhcnRoZXN0PyoqDQoNCkp1c3QgbGlrZSBhYm92ZSwgeW91IGNvdWxkIGludGVycHJldCB0aGlzIHF1ZXN0aW9uIGFzIGJlaW5nIHJlbGF0ZWQgdG8gYWlyIHRpbWUsIGJ1dCBJIGRlY2lkZWQgdG8gZ28gd2l0aCBkaXN0YW5jZS4gSnVzdCB0byBtaXggdXAgd2hhdCBJIHdhcyBzb3J0aW5nLiANCmBgYHtyfQ0KYXJyYW5nZSAoZmxpZ2h0cywgZGVzYyhkaXN0YW5jZSkpDQpgYGANCg0KKio0Yi4gV2hpY2ggdHJhdmVsZWQgdGhlIHNob3J0ZXN0PyoqDQoNCmBgYHtyfQ0KYXJyYW5nZSAoZmxpZ2h0cywgZGlzdGFuY2UpDQpgYGANCg0KIyMgNS40LjEgRXhlcmNpc2VzDQoNCioqMS4gQnJhaW5zdG9ybSBhcyBtYW55IHdheXMgYXMgcG9zc2libGUgdG8gc2VsZWN0IGRlcF90aW1lLCBkZXBfZGVsYXksIGFycl90aW1lLCBhbmQgYXJyX2RlbGF5IGZyb20gZmxpZ2h0cy4qKg0KDQpXZWxsLCB3ZSBjYW4gZmlyc3QgZG8gaXQgdGhlIHNpbXBsZSB3YXkuIEJ5IG5hbWUuIA0KYGBge3J9DQpzZWxlY3QoZmxpZ2h0cywgZGVwX3RpbWUsIGRlcF9kZWxheSwgYXJyX3RpbWUsIGFycl9kZWxheSkNCmBgYA0KDQpZb3UgY2FuIHNlbGVjdCB0aGUgdmFyaWFibGVzIHRocm91Z2ggdGhlaXIgY29sdW1uIG51bWJlcnMuDQpgYGB7cn0NCnNlbGVjdCAoZmxpZ2h0cywgNCwgNiwgNywgOSkNCmBgYA0KDQpZb3UgY2FuIGRvIHN0YXJ0c193aXRoICgpDQpgYGB7cn0NCnNlbGVjdCAoZmxpZ2h0cywgc3RhcnRzX3dpdGgoImRlcF8iKSwgc3RhcnRzX3dpdGggKCJhcnIiKSkNCmBgYA0KDQphbGwgKG9mKSBhbmQgYW55IChvZikgLT4gYm90aCBvZiB3aGljaCB3ZSB3aWxsIHRhbGsgbW9yZSBhYm91dCBmb3IgcXVlc3Rpb24gMy4NCmBgYHtyfQ0Kc2VsZWN0IChmbGlnaHRzLCBhbGxfb2YgKGMoImRlcF90aW1lIiwgImRlcF9kZWxheSIsICJhcnJfdGltZSIsICJhcnJfZGVsYXkiKSkpDQpzZWxlY3QgKGZsaWdodHMsIGFueV9vZiAoYygiZGVwX3RpbWUiLCAiZGVwX2RlbGF5IiwgImFycl90aW1lIiwgImFycl9kZWxheSIpKSkNCmBgYA0KDQpGb3Igb3RoZXIgb3B0aW9ucywgYW5kIHRoZXkgYXJlIGFsbW9zdCAiZW5kbGVzcywiIHlvdSBjYW4gbG9vayBhdCA/c2VsZWN0LiBQbHVzLCB0aGVyZSBhcmUgb3RoZXIgd2F5cyBvZiBhcHByb2FjaGluZyB0aGlzLiANCmBgYHtyfQ0KP3NlbGVjdA0KYGBgDQoqKjIuIFdoYXQgaGFwcGVucyBpZiB5b3UgaW5jbHVkZSB0aGUgbmFtZSBvZiBhIHZhcmlhYmxlIG11bHRpcGxlIHRpbWVzIGluIGEgc2VsZWN0KCkgY2FsbD8qKg0KDQpgYGB7cn0NCnNlbGVjdCAoZmxpZ2h0cywgeWVhciwgbW9udGgsIGRheSwgZGVwX3RpbWUsIGRlcF90aW1lKQ0KYGBgDQoNCkl0IGxvb2tzIGxpa2UgaXQganVzdCBza2lwcyBvdmVyIHRoZSByZXBlYXRlZCB2YXJhaWJsZSwgc2luY2UgZGVwYXR1cmUgdGltZSB3YXMgb25seSBkaXNwbGF5ZWQgb25jZS4gDQoNCioqM2EuIFdoYXQgZG9lcyB0aGUgYW55X29mKCkgZnVuY3Rpb24gZG8/KioNCg0KYGBge3J9DQo/YW55X29mDQpgYGANCg0KSXQgYWxsb3dzIHlvdSB0byBzZWxlY3QgdmFyaWFibGUgZnJvbSBjaGFyYWN0ZXIgdmVjdG9ycywgbGlrZSB0aGF0IG9mIGFsbF9vZi4gV2hhdCBhbnlfb2YgZG9lcyBpcyBsb29rIGF0IHZhcmlhYmxlcyBjb250YWluZWQgaW4gYSBjaGFyYWN0ZXIgdmVjdG9yIHdpdGhvdXQgY2hlY2tpbmcgZm9yIG1pc3NpbmcgdmFyaWFibGVzLiBBbnlfb2YgaXMgZ3JlYXQgZm9yIGNoZWNraW5nIG5lZ2F0aXZlIHNlbGVjdGlvbnMsIGFzIGl0IHdpbGwgaWdub3JlIGFueXRoaW5nIG91dCBvZiB0aGUgJ3NvcnRzIScNCg0KKiozYi4gV2h5IG1pZ2h0IGl0IGJlIGhlbHBmdWwgaW4gY29uanVuY3Rpb24gd2l0aCB0aGlzIHZlY3Rvcj8qKg0KYGBge3J9DQp2YXJzIDwtIGMoInllYXIiLCAibW9udGgiLCAiZGF5IiwgImRlcF9kZWxheSIsICJhcnJfZGVsYXkiKQ0KYGBgDQoNCmBgYHtyfQ0Kc2VsZWN0KGZsaWdodHMsIGFueV9vZih2YXJzKSkNCmBgYA0KDQpJdCBpcyB1c2VmdWwgYmVjYXVzZSBpdCBjYW4gY3V0IHRoZSBjaGFzZSBvZiBjb25zdGFudGx5IGhhdmluZyB0byByZXR5cGUgb3V0IHRoZSB2YXJpYWJsZSBuYW1lcyBldmVyeSB0aW1lIHlvdSBhcHBseSB0aGVtLiBCeSBjcmVhdGluZyBhIHZlY3RvciB5b3UgYXJlIGFibGUgdG8gc3RyZWFtbGluZSB5b3VyIGRhdGEgYSBiaXQgZm9yIGJvdGggZWFzZSBhbmQgZm9yIGJlaW5nIGJldHRlciBjb25zaXN0ZW50LiANCg0KKio0YS4gRG9lcyB0aGUgcmVzdWx0IG9mIHJ1bm5pbmcgdGhlIGZvbGxvd2luZyBjb2RlIHN1cnByaXNlIHlvdT8qKg0KYGBge3J9DQpzZWxlY3QoZmxpZ2h0cywgY29udGFpbnMoIlRJTUUiKSkNCmBgYA0KDQpBIGJpdD8gTG9va2luZyBtb3JlIGludG8gdGhlIGZ1bmN0aW9uIGFmdGVyd2FyZHMsIGl0IG1ha2VzIHBsZW50eSBvZiBzZW5zZS4gRXZlcnl0aGluZyBpbiBSIGlzIGdlbmVyYWxseSBjYXNlIHNlbnNpdGl2ZSwgYnV0IGNvbnRhaW5zIGlnbm9yZXMgdGhhdC4gSW4gdGhlIGNhc2Ugb2YgdGhpcyBjb2RlLCBpdCBsb29rcyBmb3IgYW55dGhpbmcgaW4geW91ciBkYXRhIGZyYW1lIHRoYXQgY29udGFpbnMgInRpbWUuIiBObyBtYXR0ZXIgdGhlIGNhc2UgaW52b2x2ZWQuDQoNCioqNGIuIEhvdyBkbyB0aGUgc2VsZWN0IGhlbHBlcnMgZGVhbCB3aXRoIGNhc2UgYnkgZGVmYXVsdD8qKg0KDQpUaGlzIGlzIGVzc2VudGlhbGx5IGluIHBsYWNlIHRvIG1ha2Ugc3VyZSB0aGF0IG5vdGhpbmcgaXMgbGVmdCBvdXQgdW5pbnRlbnRpb25hbGx5LiBJIGJlbGlldmUgaXQgaXMganVzdCB0byBtYWtlIHRoZSB1c2VyIGludGVyZmFjZSBlYXNpZXIsIGFuZCBoZWxwcyBhbGxpdmF0ZSBhbnkgcG90ZW50aWFsIGh1bWFuIGVycm9yLiANCg0KKio0Yy4gSG93IGNhbiB5b3UgY2hhbmdlIHRoYXQgZGVmYXVsdD8qKg0KDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCBjb250YWlucygiVElNRSIsIGlnbm9yZS5jYXNlID0gRkFMU0UpKQ0KYGBg