Solutions to this workshop can be found here
Testing functions
One really critical point is that you really need test any new functions extensively. It is incredibly easy to make a mistake in coding (think about all the typos you’ve ever made, except this time they can critically affect the results of your data analysis). The solution to this is testing any code you write extensively, and if possible, having another coder familiar with what you’re doing look over it (which means always including tons of comments!)
Before we do anything else, we’ll need to load in the function we created last time to grow plants, since we’re going to be re-using this. To do this, run the source()
command, with the full path to grow_plants.R as the argument
source('~/Documents/Teaching/Intro_R_Course/grow_plants.R')
Now, let’s run some tests.
Another great sanity check in coding anything related to data is plotting. Try making a plot of your data, plotting height vs day for all the plants.
Loops
Introduction to loops
We now have a function that allows us to ‘grow’ the plants in our dataframe in a single line, just by providing the growth parameters. However, this doesn’t actually solve our problem of trying to model the growth of these plants over long periods of time. We ideally want to avoid running this model by hand 30+ times.
Instead, we can use something called a “loop”. These are an incredibly fundamental idea in programming, and they allow you to easily repeat a task multiple times.
for
loops
The most commonly used type of loop is a ‘for’ loop. Imagine we have some list (e.g. a consecutive list of days). The loop takes a variable and takes turns assigning every value from the list to it, in order, and then doing something with the variable. Here’s how they look in R:
for (variable_from_list in some_list){
# do some stuff using variable_from_list
}
Note that unlike functions, loops are not closed-off boxes: in addition to variable_from_list, they have access to all the previously specified variables in R, and they can modify these variables.
Let’s try an example: we can write a loop that starts with a vector of numbers, and produces an output vector of those numbers squared.
initial_vector <- c(0, 3, -2, 4, 15)
squares_vector <- c()
for(current_number in initial_vector){
print(current_number)
current_number_squared <- current_number^2
squares_vector <- c(squares_vector, current_number_squared)
}
print(squares_vector)
Of course, you don’t need a loop to do the above; simply running initial_vector^2
would have worked. In fact, running this kind of operation in the loop we wrote takes much longer than the alternative. However, there are many cases (like our plant growth problem) where loops are the only way to do something.
while
loops
There’s also another kind of loop, a ‘while’ loop. Rather than going through a vector of pre-defined length, while loops check that some condition is true, and only continue while that is the case.
Here’s a while loop that subtracts 2 from a number and prints the result, stopping only when the result is equal to 0.
number <- 8
while (number != 0){
number <- number - 2
print(number)
}
while()
loops are tricky, however. If you don’t think carefully about your starting condition, you can end up in an endless loop. For example, try changing the initial value of number
to 7 in the loop above.
Hint: You can press inside your console and hold down ctrl-c
or Esc
to end the execution of any R code.
Coding plant growth in a loop
Now that we know how to write loops, try to write some code that makes a new dataframe, plant_growth_df_2, and then uses a loop running the grow_plants function to loop through 30 days of plant growth.
Putting it all together: Using simulations to plan experiments
Let’s come back to our initial problem. We want to figure out whether salt affects plant growth. To do this, we plan to compare two conditions: plants grown without salt, and plants grown with some standard concentration of salt added to the soil.
Imagine we suspect, based on previous literature, that salt decreases plant growth rate by 20%. How large of an experiment would we have to do to see this change? How long do we need to run this experiment for?
We can try to get ballpark answers to these questions with simulations.
First, let’s convert our plant dataframe-creating loop from above into a function. In addition to all the plant growth parameters, we may want to pass the number of individual plants we’re growing, as well as the duration of growth, into this function.
Now we can use our new simulate_growth()
function to simulate plant growth with and without salt.
Now that we’ve simulated our data, we can do some plotting and statistical analysis on it!
combined_plant_df$plant.id.full <-
paste(combined_plant_df$Condition, combined_plant_df$plant.id)
View(combined_plant_df)
What would you do if you wanted to repeat this simulation and comparison 1000 times, saving the p-value associated with the effect of Condition each time?
Using coding in science
I wanted to share some final resources that I think are great places to look to keep going with learning to code.
SoftwareCarpentry: Sets of lessons on the coding, mostly at an introductory/early intermediate level. Lots of overlap with this course in the R sections, but presented in a different way; also courses in Python, Unix, and really useful tools like GitHub
Jenny Bryan’s UBC’s STAT545 course: walks you through intro- and intermediate-level R, explaining not just the programming, but good ways to think about analyzing data and coding the analysis. If you want a more in-depth course about R in general, I highly recommend this.
If you’re planning to spend a lot of time coding (i.e. not just a one-off analysis, but more long-term projects), the following articles are great sources for thinking about what to aspire to. They can be daunting if you try to achieve all their suggestions at once, but I think as they both try to point out, a better idea is understanding what good, reproducible coding looks like and then slowly building more and more of these practices into your work as you grow. Few coding projects in biology manage to achieve everything outlined here, but these articles provide an excellent long-term roadmap as you become a better coder.
LS0tCnRpdGxlOiAiSW50cm8gUiBDb3Vyc2UsIFdvcmtzaG9wIDk6IEJhc2ljcyBvZiBwcm9ncmFtbWluZywgYW5kIHNpbXVsYXRpb24gaW4gYmlvbG9neSAoUGFydCBJSSkiCnN1YnRpdGxlOiB8CiAgICB8ICAgLSBzaW11bGF0aW5nIGJpb2xvZ2ljYWwgZGF0YSAoY29udGludWVkKQogICAgfCAgIC0gdGVzdGluZyBmdW5jdGlvbnMKICAgIHwgICAtIGxvb3BzCiAgICB8ICAgLSB1c2luZyBzaW11bGF0aW9ucyB0byBwbGFuIGV4cGVyaW1lbnRzCiAgICB8ICAgLSBhZGRpdGlvbmFsIHJlc291cmNlcwphdXRob3I6CiAgLSBFdWdlbmUgUGxhdnNraW4Kb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRlcHRoOiAzCiAgICB0aWR5OiB5ZXMKICAgIHRvYzogeWVzCi0tLQoqKlNvbHV0aW9ucyB0byB0aGlzIHdvcmtzaG9wIGNhbiBiZSBmb3VuZCBbaGVyZV0oU29sdXRpb25zX1dvcmtzaG9wXzkubmIuaHRtbCkqKgoKIyBUZXN0aW5nIGZ1bmN0aW9ucwoKT25lIHJlYWxseSBjcml0aWNhbCBwb2ludCBpcyB0aGF0IHlvdSByZWFsbHkgbmVlZCB0ZXN0IGFueSBuZXcgZnVuY3Rpb25zIGV4dGVuc2l2ZWx5LiBJdCBpcyAqKmluY3JlZGlibHkqKiBlYXN5IHRvIG1ha2UgYSBtaXN0YWtlIGluIGNvZGluZyAodGhpbmsgYWJvdXQgYWxsIHRoZSB0eXBvcyB5b3UndmUgZXZlciBtYWRlLCBleGNlcHQgdGhpcyB0aW1lIHRoZXkgY2FuIGNyaXRpY2FsbHkgYWZmZWN0IHRoZSByZXN1bHRzIG9mIHlvdXIgZGF0YSBhbmFseXNpcykuIFRoZSBzb2x1dGlvbiB0byB0aGlzIGlzIHRlc3RpbmcgYW55IGNvZGUgeW91IHdyaXRlIGV4dGVuc2l2ZWx5LCBhbmQgaWYgcG9zc2libGUsIGhhdmluZyBhbm90aGVyIGNvZGVyIGZhbWlsaWFyIHdpdGggd2hhdCB5b3UncmUgZG9pbmcgbG9vayBvdmVyIGl0ICh3aGljaCBtZWFucyBhbHdheXMgaW5jbHVkaW5nIHRvbnMgb2YgY29tbWVudHMhKQoKQmVmb3JlIHdlIGRvIGFueXRoaW5nIGVsc2UsIHdlJ2xsIG5lZWQgdG8gbG9hZCBpbiB0aGUgZnVuY3Rpb24gd2UgY3JlYXRlZCBsYXN0IHRpbWUgdG8gZ3JvdyBwbGFudHMsIHNpbmNlIHdlJ3JlIGdvaW5nIHRvIGJlIHJlLXVzaW5nIHRoaXMuIFRvIGRvIHRoaXMsIHJ1biB0aGUgYHNvdXJjZSgpYCBjb21tYW5kLCB3aXRoIHRoZSBmdWxsIHBhdGggdG8gKmdyb3dfcGxhbnRzLlIqIGFzIHRoZSBhcmd1bWVudApgYGB7cn0KIyBzb21ldGhpbmcgbGlrZSB0aGlzCnNvdXJjZSgnfi9Eb2N1bWVudHMvVGVhY2hpbmcvSW50cm9fUl9Db3Vyc2UvZ3Jvd19wbGFudHMuUicpCmBgYAoKTm93LCBsZXQncyBydW4gc29tZSB0ZXN0cy4KYGBge3J9CiMgc2V0IHRoZSB2YXJpYWJsZXMgeW91J2xsIHVzZSBmb3IgcGxhbnQgZ3Jvd3RoCiMgKHNhbXBsZV9zaXplLCBwbGFudF9ncm93dGhfcGVyX2RheSwgcGxhbnRfZ3Jvd3RoX3NkKQoKIyByZS1pbml0aWFsaXplIHBsYW50X2dyb3d0aF9kZiBhdCBkYXkgMCwgYXMgeWVzdGVyZGF5CgojIFRlc3QgeW91ciBmdW5jdGlvbiBvbiBwbGFudF9ncm93dGhfZGYsIGFkZGluZyBhIGRheSBvZiBncm93dGggYW5kCiMgY2hlY2tpbmcgdGhhdCB0aGUgcmVzdWx0cyBsb29rIGxpa2UgeW91J2QgZXhwZWN0CiMgRmlyc3QsIHRlc3Qgd2hhdCBoYXBwZW5zIGlmIHlvdSBzZXQgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUKIyBkYWlseSBncm93dGggYW1vdW50IHRvIDAKCiMgTmV4dCwgc2V0IHRoZSBtZWFuIHRvIGEgbm9uLTAgbnVtYmVyLCBidXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiB0byAwCgojIEZpbmFsbHksIHRyeSBncm93aW5nIHRoZSBwbGFudHMgd2l0aCBhIG5vbi0wIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbgojIChlLmcuIHBsYW50X2dyb3d0aF9wZXJfZGF5IGFuZCBwbGFudF9ncm93dGhfc2QgZnJvbSBhYm92ZSkKCmBgYAoKQW5vdGhlciBncmVhdCBzYW5pdHkgY2hlY2sgaW4gY29kaW5nIGFueXRoaW5nIHJlbGF0ZWQgdG8gZGF0YSBpcyBwbG90dGluZy4gVHJ5IG1ha2luZyBhIHBsb3Qgb2YgeW91ciBkYXRhLCBwbG90dGluZyBoZWlnaHQgdnMgZGF5IGZvciBhbGwgdGhlIHBsYW50cy4KYGBge3J9CiMgUGxvdCBwbGFudF9ncm93dGhfZGYKCiMgSWYgeW91IHdhbnQgdG8gaW5jbHVkZSBsaW5lcyBvbiB5b3VyIHBsb3QsIHlvdSB3aWxsIGhhdmUgdG8gaW5jbHVkZSBhICJncm91cCIKIyBwYXJhbWV0ZXIgaW4geW91ciBtYXBwaW5nIChpLmUuICJncm91cCA9IHBsYW50LmlkIik7IHRoaXMgc2VwYXJhdGVzIHRoZSBkYXRhCiMgYnkgdGhlIGNhdGVnb3J5IChvciBjYXRlZ29yaWVzKSB5b3Ugc3BlY2lmeSwgd2l0aG91dCBnaXZpbmcgaXQgYSBzcGVjaWFsIGNvbG9yLAojIHNoYXBlLCBvciBhc3NvY2lhdGVkIGxlZ2VuZAoKYGBgCgojIExvb3BzCgojIyBJbnRyb2R1Y3Rpb24gdG8gbG9vcHMKCldlIG5vdyBoYXZlIGEgZnVuY3Rpb24gdGhhdCBhbGxvd3MgdXMgdG8gJ2dyb3cnIHRoZSBwbGFudHMgaW4gb3VyIGRhdGFmcmFtZSBpbiBhIHNpbmdsZSBsaW5lLCBqdXN0IGJ5IHByb3ZpZGluZyB0aGUgZ3Jvd3RoIHBhcmFtZXRlcnMuIEhvd2V2ZXIsIHRoaXMgZG9lc24ndCBhY3R1YWxseSBzb2x2ZSBvdXIgcHJvYmxlbSBvZiB0cnlpbmcgdG8gbW9kZWwgdGhlIGdyb3d0aCBvZiB0aGVzZSBwbGFudHMgb3ZlciBsb25nIHBlcmlvZHMgb2YgdGltZS4gV2UgaWRlYWxseSB3YW50IHRvIGF2b2lkIHJ1bm5pbmcgdGhpcyBtb2RlbCBieSBoYW5kIDMwKyB0aW1lcy4KCkluc3RlYWQsIHdlIGNhbiB1c2Ugc29tZXRoaW5nIGNhbGxlZCBhICJsb29wIi4gVGhlc2UgYXJlIGFuIGluY3JlZGlibHkgZnVuZGFtZW50YWwgaWRlYSBpbiBwcm9ncmFtbWluZywgYW5kIHRoZXkgYWxsb3cgeW91IHRvIGVhc2lseSByZXBlYXQgYSB0YXNrIG11bHRpcGxlIHRpbWVzLgoKIyMjIGBmb3JgIGxvb3BzClRoZSBtb3N0IGNvbW1vbmx5IHVzZWQgdHlwZSBvZiBsb29wIGlzIGEgJ2ZvcicgbG9vcC4gSW1hZ2luZSB3ZSBoYXZlIHNvbWUgbGlzdCAoZS5nLiBhIGNvbnNlY3V0aXZlIGxpc3Qgb2YgZGF5cykuIFRoZSBsb29wIHRha2VzIGEgdmFyaWFibGUgYW5kIHRha2VzIHR1cm5zIGFzc2lnbmluZyBldmVyeSB2YWx1ZSBmcm9tIHRoZSBsaXN0IHRvIGl0LCBpbiBvcmRlciwgYW5kIHRoZW4gZG9pbmcgc29tZXRoaW5nIHdpdGggdGhlIHZhcmlhYmxlLiBIZXJlJ3MgaG93IHRoZXkgbG9vayBpbiBSOgpgYGB7fQpmb3IgKHZhcmlhYmxlX2Zyb21fbGlzdCBpbiBzb21lX2xpc3QpewogICMgZG8gc29tZSBzdHVmZiB1c2luZyB2YXJpYWJsZV9mcm9tX2xpc3QKfQpgYGAKTm90ZSB0aGF0IHVubGlrZSBmdW5jdGlvbnMsIGxvb3BzIGFyZSAqbm90KiBjbG9zZWQtb2ZmIGJveGVzOiBpbiBhZGRpdGlvbiB0byB2YXJpYWJsZV9mcm9tX2xpc3QsIHRoZXkgaGF2ZSBhY2Nlc3MgdG8gYWxsIHRoZSBwcmV2aW91c2x5IHNwZWNpZmllZCB2YXJpYWJsZXMgaW4gUiwgYW5kIHRoZXkgY2FuIG1vZGlmeSB0aGVzZSB2YXJpYWJsZXMuCgpMZXQncyB0cnkgYW4gZXhhbXBsZTogd2UgY2FuIHdyaXRlIGEgbG9vcCB0aGF0IHN0YXJ0cyB3aXRoIGEgdmVjdG9yIG9mIG51bWJlcnMsIGFuZCBwcm9kdWNlcyBhbiBvdXRwdXQgdmVjdG9yIG9mIHRob3NlIG51bWJlcnMgc3F1YXJlZC4KYGBge3J9CiMgbnVtYmVycyB0byBsb29wIHRocm91Z2gKaW5pdGlhbF92ZWN0b3IgPC0gYygwLCAzLCAtMiwgNCwgMTUpCgojIG5lZWQgdG8gaW5pdGlhbGl6ZSBhbiBlbXB0eSB2ZWN0b3IgaW50byB3aGljaCB3ZSB3aWxsIHB1dCB0aGUgc29sdXRpb25zIGluCiMgZWFjaCBsb29wIHJvdW5kCnNxdWFyZXNfdmVjdG9yIDwtIGMoKQoKIyBsb29wIG92ZXIgaW5pdGlhbF92ZWN0b3IsIGFuZCBwb3B1bGF0ZSBzcXVhcmVfdmVjdG9yCmZvcihjdXJyZW50X251bWJlciBpbiBpbml0aWFsX3ZlY3Rvcil7CiAgIyBwcmludCBjdXJyZW50X251bWJlciwganVzdCBzbyB3ZSBjYW4gc2VlIHdoYXQgdmFsdWVzIGl0IHRha2VzIG9uCiAgcHJpbnQoY3VycmVudF9udW1iZXIpCiAgIyBub3RpY2UgdGhhdCBjdXJyZW50X251bWJlciB3aWxsIHRha2UgdHVybnMgaG9sZGluZyBldmVyeSB2YWx1ZSBvZiBpbml0aWFsX3ZlY3RvcgogIGN1cnJlbnRfbnVtYmVyX3NxdWFyZWQgPC0gY3VycmVudF9udW1iZXJeMgogICMgYWRkIGN1cnJlbnRfbnVtYmVyX3NxdWFyZWQgdG8gdGhlIGVuZCBvZiBzcXVhcmVzX3ZlY3RvcgogIHNxdWFyZXNfdmVjdG9yIDwtIGMoc3F1YXJlc192ZWN0b3IsIGN1cnJlbnRfbnVtYmVyX3NxdWFyZWQpCn0KcHJpbnQoc3F1YXJlc192ZWN0b3IpCmBgYApPZiBjb3Vyc2UsIHlvdSBkb24ndCBuZWVkIGEgbG9vcCB0byBkbyB0aGUgYWJvdmU7IHNpbXBseSBydW5uaW5nIGBpbml0aWFsX3ZlY3Rvcl4yYCB3b3VsZCBoYXZlIHdvcmtlZC4gSW4gZmFjdCwgcnVubmluZyB0aGlzIGtpbmQgb2Ygb3BlcmF0aW9uIGluIHRoZSBsb29wIHdlIHdyb3RlIHRha2VzICptdWNoKiBsb25nZXIgdGhhbiB0aGUgYWx0ZXJuYXRpdmUuIEhvd2V2ZXIsIHRoZXJlIGFyZSBtYW55IGNhc2VzIChsaWtlIG91ciBwbGFudCBncm93dGggcHJvYmxlbSkgd2hlcmUgbG9vcHMgYXJlIHRoZSBvbmx5IHdheSB0byBkbyBzb21ldGhpbmcuCgojIyMgYHdoaWxlYCBsb29wcwoKVGhlcmUncyBhbHNvIGFub3RoZXIga2luZCBvZiBsb29wLCBhICd3aGlsZScgbG9vcC4gUmF0aGVyIHRoYW4gZ29pbmcgdGhyb3VnaCBhIHZlY3RvciBvZiBwcmUtZGVmaW5lZCBsZW5ndGgsIHdoaWxlIGxvb3BzIGNoZWNrIHRoYXQgc29tZSBjb25kaXRpb24gaXMgdHJ1ZSwgYW5kIG9ubHkgY29udGludWUgKndoaWxlKiB0aGF0IGlzIHRoZSBjYXNlLgoKSGVyZSdzIGEgd2hpbGUgbG9vcCB0aGF0IHN1YnRyYWN0cyAyIGZyb20gYSBudW1iZXIgYW5kIHByaW50cyB0aGUgcmVzdWx0LCBzdG9wcGluZyBvbmx5IHdoZW4gdGhlIHJlc3VsdCBpcyBlcXVhbCB0byAwLgpgYGB7cn0KIyBpbml0aWFsaXplIHRoZSB3aGlsZSBsb29wCm51bWJlciA8LSA4CndoaWxlIChudW1iZXIgIT0gMCl7CiAgbnVtYmVyIDwtIG51bWJlciAtIDIKICBwcmludChudW1iZXIpCn0KYGBgCmB3aGlsZSgpYCBsb29wcyBhcmUgdHJpY2t5LCBob3dldmVyLiBJZiB5b3UgZG9uJ3QgdGhpbmsgY2FyZWZ1bGx5IGFib3V0IHlvdXIgc3RhcnRpbmcgY29uZGl0aW9uLCB5b3UgY2FuIGVuZCB1cCBpbiBhbiBlbmRsZXNzIGxvb3AuIEZvciBleGFtcGxlLCB0cnkgY2hhbmdpbmcgdGhlIGluaXRpYWwgdmFsdWUgb2YgYG51bWJlcmAgdG8gNyBpbiB0aGUgbG9vcCBhYm92ZS4KCioqSGludCoqOiBZb3UgY2FuIHByZXNzIGluc2lkZSB5b3VyIGNvbnNvbGUgYW5kIGhvbGQgZG93biBgY3RybC1jYCBvciBgRXNjYCB0byBlbmQgdGhlIGV4ZWN1dGlvbiBvZiBhbnkgUiBjb2RlLgoKIyMgQ29kaW5nIHBsYW50IGdyb3d0aCBpbiBhIGxvb3AKCk5vdyB0aGF0IHdlIGtub3cgaG93IHRvIHdyaXRlIGxvb3BzLCB0cnkgdG8gd3JpdGUgc29tZSBjb2RlIHRoYXQgbWFrZXMgYSBuZXcgZGF0YWZyYW1lLCBwbGFudF9ncm93dGhfZGZfMiwgYW5kIHRoZW4gdXNlcyBhIGxvb3AgcnVubmluZyB0aGUgZ3Jvd19wbGFudHMgZnVuY3Rpb24gdG8gbG9vcCB0aHJvdWdoIDMwIGRheXMgb2YgcGxhbnQgZ3Jvd3RoLgpgYGB7cn0KIyBJbml0aWFsaXplIHBsYW50X2dyb3d0aF9kZl8yIGZvciBkYXkgMAoKIyBMb29wIHRocm91Z2ggZGF5cyAxLTMwLCBhZGRpbmcgdG8gcGxhbnQgZ3Jvd3RoCgojIHBsb3QgcGxhbnQgZ3Jvd3RoIG92ZXIgdGltZQoKYGBgCgojIFB1dHRpbmcgaXQgYWxsIHRvZ2V0aGVyOiBVc2luZyBzaW11bGF0aW9ucyB0byBwbGFuIGV4cGVyaW1lbnRzCgpMZXQncyBjb21lIGJhY2sgdG8gb3VyIGluaXRpYWwgcHJvYmxlbS4gV2Ugd2FudCB0byBmaWd1cmUgb3V0IHdoZXRoZXIgc2FsdCBhZmZlY3RzIHBsYW50IGdyb3d0aC4gVG8gZG8gdGhpcywgd2UgcGxhbiB0byBjb21wYXJlIHR3byBjb25kaXRpb25zOiBwbGFudHMgZ3Jvd24gd2l0aG91dCBzYWx0LCBhbmQgcGxhbnRzIGdyb3duIHdpdGggc29tZSBzdGFuZGFyZCBjb25jZW50cmF0aW9uIG9mIHNhbHQgYWRkZWQgdG8gdGhlIHNvaWwuCgpJbWFnaW5lIHdlIHN1c3BlY3QsIGJhc2VkIG9uIHByZXZpb3VzIGxpdGVyYXR1cmUsIHRoYXQgc2FsdCBkZWNyZWFzZXMgcGxhbnQgZ3Jvd3RoIHJhdGUgYnkgMjAlLiBIb3cgbGFyZ2Ugb2YgYW4gZXhwZXJpbWVudCB3b3VsZCB3ZSBoYXZlIHRvIGRvIHRvIHNlZSB0aGlzIGNoYW5nZT8gSG93IGxvbmcgZG8gd2UgbmVlZCB0byBydW4gdGhpcyBleHBlcmltZW50IGZvcj8KCldlIGNhbiB0cnkgdG8gZ2V0IGJhbGxwYXJrIGFuc3dlcnMgdG8gdGhlc2UgcXVlc3Rpb25zIHdpdGggc2ltdWxhdGlvbnMuCgpGaXJzdCwgbGV0J3MgY29udmVydCBvdXIgcGxhbnQgZGF0YWZyYW1lLWNyZWF0aW5nIGxvb3AgZnJvbSBhYm92ZSBpbnRvIGEgZnVuY3Rpb24uIEluIGFkZGl0aW9uIHRvIGFsbCB0aGUgcGxhbnQgZ3Jvd3RoIHBhcmFtZXRlcnMsIHdlIG1heSB3YW50IHRvIHBhc3MgdGhlIG51bWJlciBvZiBpbmRpdmlkdWFsIHBsYW50cyB3ZSdyZSBncm93aW5nLCBhcyB3ZWxsIGFzIHRoZSBkdXJhdGlvbiBvZiBncm93dGgsIGludG8gdGhpcyBmdW5jdGlvbi4KYGBge3J9CiMgV3JpdGUgYSBmdW5jdGlvbiwgc2ltdWxhdGVfZ3Jvd3RoLCB0aGF0IHRha2VzIGluIG1lYW4gYW5kIHMuZC4gb2YgZGFpbHkgcGxhbnQKIyBncm93dGgsIHRoZSBudW1iZXIgb2YgcGxhbnRzIHRvIHNpbXVsYXRlLCBhbmQgdGhlIG51bWJlciBvZiBkYXlzIHRvICdncm93JwojIHRoZSBwbGFudHMgZm9yCiMgT3V0cHV0IHNob3VsZCBiZSBhIGRhdGFmcmFtZSBvZiBwbGFudCBoZWlnaHRzIG92ZXIgdGltZQoKYGBgCgpOb3cgd2UgY2FuIHVzZSBvdXIgbmV3IGBzaW11bGF0ZV9ncm93dGgoKWAgZnVuY3Rpb24gdG8gc2ltdWxhdGUgcGxhbnQgZ3Jvd3RoIHdpdGggYW5kIHdpdGhvdXQgc2FsdC4KYGBge3J9CiMgQ3JlYXRlIHZhcmlhYmxlcyBmb3IgbWVhbiBkYWlseSBncm93dGggYW1vdW5nIHdpdGggYW5kIHdpdGhvdXQgc2FsdCwgcy5kLiBvZgojIGRhaWx5IGdyb3d0aCwgIyBvZiBwbGFudHMgdG8gc2ltdWxhdGUsIGFuZCBudW1iZXIgb2YgZGF5cyB0byBncm93IHRoZSBwbGFudHMKCiMgVXNlIHRoZSB2YXJpYWJsZXMgYWJvdmUgdG8gY3JlYXRlIHR3byBkYXRhZnJhbWVzOiBncm93dGhfd2l0aF9zYWx0LCBhbmQKIyBncm93dGhfbm9fc2FsdAoKIyBBZGQgYSAnQ29uZGl0aW9uJyBjb2x1bW4gdG8gZWFjaCBvZiB0aGUgbmV3IGRhdGFmcmFtZXMgdGhhdCB3aWxsIHNheSB3aGV0aGVyCiMgb3Igbm90IHNhbHQgd2FzIHVzZWQKCiMgVXNlIHJiaW5kIHRvIGNvbWJpbmUgdGhlIHR3byBkYXRhZnJhbWVzIGludG8gYSBuZXcgZGF0YWZyYW1lLCBjb21iaW5lZF9wbGFudF9kZgoKYGBgCgpOb3cgdGhhdCB3ZSd2ZSBzaW11bGF0ZWQgb3VyIGRhdGEsIHdlIGNhbiBkbyBzb21lIHBsb3R0aW5nIGFuZCBzdGF0aXN0aWNhbCBhbmFseXNpcyBvbiBpdCEKYGBge3J9CiMgUGxvdCB0aGUgdGltZWNvdXJzZSBkYXRhIGZyb20gY29tYmluZWRfcGxhbnRfZGYgaW4gYSB1c2VmdWwgd2F5CiMgKGNvbG9yaW5nIGJ5IENvbmRpdGlvbiwgd2l0aCBhbiBpbmRpdmlkdWFsIGxpbmUgZm9yIGVhY2ggcGxhbnQpCgojIFRoaXMgbWF5IG5vdCBoYXZlIHdvcmtlZCBhcyB5b3UgZXhwZWN0ZWQgYmVjYXVzZSBhcyBmYXIgYXMgZ2dwbG90IGlzIGNvbmNlcm5lZCwKIyB0aGUgaW5kaXZpZHVhbHMgbGFiZWxlZCAiMSIgYXJlIGFsbCB0aGUgc2FtZSBpbmRpdmlkdWFsLCByZWdhcmRsZXNzIG9mIHdoZXRoZXIKIyB0aGV5IGNvbWUgZnJvbSB0aGUgc2FsdCBjb25kaXRpb24gb3Igbm90LiBXZSBoYXZlIHRvIHRlbGwgZ2dwbG90IHRoaXMgaXMgbm90CiMgdGhlIGNhc2UKY29tYmluZWRfcGxhbnRfZGYkcGxhbnQuaWQuZnVsbCA8LQogIHBhc3RlKGNvbWJpbmVkX3BsYW50X2RmJENvbmRpdGlvbiwgY29tYmluZWRfcGxhbnRfZGYkcGxhbnQuaWQpClZpZXcoY29tYmluZWRfcGxhbnRfZGYpCiMgVGhpcyBpcyBhICp2ZXJ5KiBjb21tb24gcHJvYmxlbSB3aXRoIGRhdGEgdGhhdCBjb21lcyBmcm9tIG11bHRpcGxlIGV4cGVyaW1lbnRzCiMgKGUuZy4gd2VsbCBsb2NhdGlvbiBpcyB1bmlxdWUgd2l0aGluIGEgOTYtd2VsbCBwbGF0ZSwgYnV0IHlvdSBydW4gaW50bwojIHByb2JsZW1zIHdoZW4gY29tYmluaW5nIGRhdGEgZnJvbSBtdWx0aXBsZSBwbGF0ZXMpCgojIHJlcGVhdCB0aGUgcGxvdCwgdXNpbmcgdGhlIHBsYW50LmlkLmZ1bGwgY29sdW1uCgpgYGAKCmBgYHtyfQojIFVzZSBsbSB0byBtb2RlbCB0aGUgZWZmZWN0IG9mIENvbmRpdGlvbiBvbiBwbGFudCBncm93dGgsIGFuZCBjaGVjayB0aGUgb3V0cHV0CiMgSXMgdGhlIG9ic2VydmVkIGNoYW5nZSBzaWduaWZpY2FudD8KCmBgYApXaGF0IHdvdWxkIHlvdSBkbyBpZiB5b3Ugd2FudGVkIHRvIHJlcGVhdCB0aGlzIHNpbXVsYXRpb24gYW5kIGNvbXBhcmlzb24gMTAwMCB0aW1lcywgc2F2aW5nIHRoZSBwLXZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGUgZWZmZWN0IG9mIENvbmRpdGlvbiBlYWNoIHRpbWU/CgojIFVzaW5nIGNvZGluZyBpbiBzY2llbmNlCgpJIHdhbnRlZCB0byBzaGFyZSBzb21lIGZpbmFsIHJlc291cmNlcyB0aGF0IEkgdGhpbmsgYXJlIGdyZWF0IHBsYWNlcyB0byBsb29rIHRvIGtlZXAgZ29pbmcgd2l0aCBsZWFybmluZyB0byBjb2RlLgoKKiBbU29mdHdhcmVDYXJwZW50cnldKGh0dHBzOi8vc29mdHdhcmUtY2FycGVudHJ5Lm9yZy9sZXNzb25zLyk6IFNldHMgb2YgbGVzc29ucyBvbiB0aGUgY29kaW5nLCBtb3N0bHkgYXQgYW4gaW50cm9kdWN0b3J5L2Vhcmx5IGludGVybWVkaWF0ZSBsZXZlbC4gTG90cyBvZiBvdmVybGFwIHdpdGggdGhpcyBjb3Vyc2UgaW4gdGhlIFIgc2VjdGlvbnMsIGJ1dCBwcmVzZW50ZWQgaW4gYSBkaWZmZXJlbnQgd2F5OyBhbHNvIGNvdXJzZXMgaW4gUHl0aG9uLCBVbml4LCBhbmQgcmVhbGx5IHVzZWZ1bCB0b29scyBsaWtlIEdpdEh1YgoKKiBbSmVubnkgQnJ5YW4ncyBVQkMncyBTVEFUNTQ1IGNvdXJzZV0oaHR0cHM6Ly9zdGF0NTQ1LmNvbS8pOiB3YWxrcyB5b3UgdGhyb3VnaCBpbnRyby0gYW5kIGludGVybWVkaWF0ZS1sZXZlbCBSLCBleHBsYWluaW5nIG5vdCBqdXN0IHRoZSBwcm9ncmFtbWluZywgYnV0IGdvb2Qgd2F5cyB0byB0aGluayBhYm91dCBhbmFseXppbmcgZGF0YSBhbmQgY29kaW5nIHRoZSBhbmFseXNpcy4gSWYgeW91IHdhbnQgYSBtb3JlIGluLWRlcHRoIGNvdXJzZSBhYm91dCBSIGluIGdlbmVyYWwsIEkgaGlnaGx5IHJlY29tbWVuZCB0aGlzLgoKSWYgeW91J3JlIHBsYW5uaW5nIHRvIHNwZW5kIGEgbG90IG9mIHRpbWUgY29kaW5nIChpLmUuIG5vdCBqdXN0IGEgb25lLW9mZiBhbmFseXNpcywgYnV0IG1vcmUgbG9uZy10ZXJtIHByb2plY3RzKSwgdGhlIGZvbGxvd2luZyBhcnRpY2xlcyBhcmUgZ3JlYXQgc291cmNlcyBmb3IgdGhpbmtpbmcgYWJvdXQgd2hhdCB0byBhc3BpcmUgdG8uIFRoZXkgY2FuIGJlIGRhdW50aW5nIGlmIHlvdSB0cnkgdG8gYWNoaWV2ZSBhbGwgdGhlaXIgc3VnZ2VzdGlvbnMgYXQgb25jZSwgYnV0IEkgdGhpbmsgYXMgdGhleSBib3RoIHRyeSB0byBwb2ludCBvdXQsIGEgYmV0dGVyIGlkZWEgaXMgdW5kZXJzdGFuZGluZyB3aGF0IGdvb2QsIHJlcHJvZHVjaWJsZSBjb2RpbmcgbG9va3MgbGlrZSBhbmQgdGhlbiBzbG93bHkgYnVpbGRpbmcgbW9yZSBhbmQgbW9yZSBvZiB0aGVzZSBwcmFjdGljZXMgaW50byB5b3VyIHdvcmsgYXMgeW91IGdyb3cuIEZldyBjb2RpbmcgcHJvamVjdHMgaW4gYmlvbG9neSBtYW5hZ2UgdG8gYWNoaWV2ZSAqZXZlcnl0aGluZyogb3V0bGluZWQgaGVyZSwgYnV0IHRoZXNlIGFydGljbGVzIHByb3ZpZGUgYW4gZXhjZWxsZW50IGxvbmctdGVybSByb2FkbWFwIGFzIHlvdSBiZWNvbWUgYSBiZXR0ZXIgY29kZXIuCgoqIFtQYXJrZXIsIEhpbGxhcnkuICgyMDE3KSBPcGluaW9uYXRlZCBBbmFsYXlzaXMgRGV2ZWxvcG1lbnQgKlBlZXJKIFByZXByaW50cyA1OmUzMjEwdjEqXShodHRwczovL3BlZXJqLmNvbS9wcmVwcmludHMvMzIxMC8pCgoqIFtXaWxzb24sIEdyZWcgKmV0IGFsLiogKDIwMTcpIEdvb2QgZW5vdWdoIHByYWN0aWNlcyBpbiBzY2llbnRpZmljIGNvbXB1dGluZy4gKlBMT1MgQ29tcHV0YXRpb25hbCBCaW9sb2d5IDEzKDYpOiBlMTAwNTUxMCpdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMzcxL2pvdXJuYWwucGNiaS4xMDA1NTEwKQoK