Making Interactive Case Studies Tutorial

 

1. Setting Up


www Directory


Only the files in this www directory will be published with the index.Rmd.

In this www directory, we need to have:

  • style.css
  • GA_Script.Rhtml
  • move the data, docs, img, etc. directories of the static version into the www directory. These directories contain the files needed to render the index.Rmd file.
  • Additionally, we need to make an exercise sub-directory. This is where we would put the .rda files for the “setup” of the exercises.

YAML Header


Refer to the YAML header of this .Rmd file.

Important notes (the followings are different from the static version):

  • title
  • css: www/style.css (the statics version does not have the www directory)
  • in_header: www/GA_Script.Rhtml (the statics version does not have the www directory)
  • the addition of runtime: shiny_prerendered

R Setup Chunk


Refer to the setup chunk of this .Rmd file.

The main difference here is the addition of the the following libraries:

library(learnr)
library(gradethis)
gradethis::gradethis_setup()

Note: you might need to install gradethis from github

Translate


Use the following code for translation

<div align="left" id="google_translate_element",></div>

<script type="text/javascript" src='//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit'></script>

<script type="text/javascript">
function googleTranslateElementInit() {
  new google.translate.TranslateElement({pageLanguage: 'en'}, 'google_translate_element');
}
</script>

Note: this is different from the statics version. There is an extra “comma” at the end of id="google_translate_element". The translation tool would not work without this comma (not sure why).

Table of Content


You might want to get rid of the following css code from the static version

<style>
#TOC {
  background: url("https://opencasestudies.github.io/img/icon-bahi.png");
  background-size: contain;
  padding-top: 240px !important;
  background-repeat: no-repeat;
}
</style>

Unlike in the static version, this would not add the logo to the table of content in the interactive app. Could work on how to add logo to the toc for interactive apps.

Optional: Add exercise_block to www/style.css


You could add a specific style for the exercises by adding the following code to the style.css file:

.exercise_block {
    padding: .5em;
    border: 1px solid lightgrey;
    background: white;
    color: black;
}

This is what the exercise block looks like. You might modify it if you want.

2. Modifications of the Static Version


data, docs, img, etc. Directories are now Sub-Directories of www


The file paths in the case study index.Rmd file that refer to these directories will need to be edited to reflect the new parent directory www. There are two cases of code chunks that will need to be edited slightly differently. I will use some examples to explain this. A quick way to find where needs to be modified is to do CTRL + F and search for here(

Case 1: Static version chunk set to echo = FALSE


When the static version has echo = FALSE:


Simply add the www directory to the interactive version:


Case 2: Static version chunk not set to echo = FALSE


When the static version does not have echo = FALSE:


Set the original chunk to eval = FALSE and the new chunk to echo = FALSE in the interactive version:


3. Add Exercises


Each exercise chunk should have their own name. For example, dw_code1 for the first coding problem embedded in the analysis of the “Data Wrangling” section, dw_quiz for the quiz of the “Data Wrangling” section, dv_exercise1 for the first coding exercise of the “Exercise” subsection of the “Data Visualization” section, etc.

Coding Problems Embedded in the Analyses


These could be the “Question Opportunities” ,or when an analysis is repeated with a different dataset and we want the students to come up with the code using what they learned, etc.

  • First, before the exercise setup chunk, we need to save the dataset needed in the exercise as a .rda file and put it in the exercise sub-directory of the www folder.
  • Then, in the exercise setup chunk, we need to load whatever libraries needed for this exercise that are not loaded in the index.Rmd setup chunk. In addition, we need to load the .rda made in the first step.
  • Then, we can start making the exercise.
  • Finally, when necessary, after the exercise, we can make a click to expend section containing the code and the output so that students may choose to skip these exercises.

Here is an example from the obesity case study:

The Exercise Subsection


Each section (data wrangling, data visualization, etc.) could have their “Exercise” subsection as the last subsection.

Quizzes


Following is an example from the CO2 case study:

Coding Exercise


  • Following is an example from the CO2 case study without use of the gradethis package:

We have created a dataset called wide_format that is in “wide” format. Write some code to convert it to “long” format. (We want 3 columns with names “ID”, “Variable”, and “Value”.)

wide_format
  ID Year Length
1  1 2015   20.0
2  2 2018   21.5
3  3 2019   19.0
wide_format %>%
  pivot_longer()
wide_format %>%
  pivot_longer(cols = -ID, names_to = "Variable", values_to = "Value")

 

  • Following is an example from the CO2 case study with use of the gradethis package:

mtcars is a built-in R dataset as shown below. Use this dataset to complete the following exercise.

mtcars
                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2

Write some code that will:

  1. Create a new dataset called new.mtcars from mtcars.
  2. Create a new column called car in new.mtcars that uses the values from the row names of mtcars. (Use the rownames_to_column function from the tibble package. See documentation here.)
  3. Only keep the car, mpg, and cyl columns of this new.mtcars dataset.
  4. Only keep the cars that have cyl = 4.
  5. Rearrange the dataset by mpg in descending order.

Note: replace the underscores(“_”) with your code with one character per “_”. Click “Submit Answer” to check your answer.

# step 1
new.mtcars <- mtcars %>%
  # step 2
  rownames_to_column(var = "___") %>%
  # step 3
  ______(___, ___, ___) %>%
  # step 4
  ______(___ == _) %>%
  # step 5
  _______(____(mpg))

# view data (Do NOT include this part when submitting your answer!)
# new.mtcars
# step 2:
# The "var" argument is the name of the new column that will use the values from the row names. What is the column name?
# step 2:
# The "var" argument is the name of the new column that will use the values from the row names. What is the column name?

# step 3:
# Which function of the "dplyr" package select columns?
# step 2:
# The "var" argument is the name of the new column that will use the values from the row names. What is the column name?

# step 3:
# Which function of the "dplyr" package select columns?

# step 4:
# Which function of the "dplyr" package subset rows?
# step 2:
# The "var" argument is the name of the new column that will use the values from the row names. What is the column name?

# step 3:
# Which function of the "dplyr" package select columns?

# step 4:
# Which function of the "dplyr" package subset rows?

# step 5:
# Which function of the "dplyr" package will reorder the data?
# What argument do we need to reorder in descending order?
# Next hint will show you the solution
new.mtcars <- mtcars %>%
  rownames_to_column(var = "car") %>%
  select(car, mpg, cyl) %>%
  filter(cyl == 4) %>%
  arrange(desc(mpg))

4. Maintenance Notes


See the maintenance_notes.Rmd file as an example.

Make sure to list the names of the exercise chunks for future maintenance. Except for things mentioned in this tutorial, other changes should be noted as well.

5. Publishing


Make sure the rsconnect folder is also pushed to GitHub.
LS0tCnRpdGxlOiB8CiAgIVtdKHd3dy9pbWcvaW50ZXJhY3RpdmVfbG9nby5wbmcpe3dpZHRoPTEyMHB4IGFsaWduPWxlZnQgc3R5bGU9InBhZGRpbmctcmlnaHQ6IDIwcHgifQogIE1ha2luZyBJbnRlcmFjdGl2ZSBDYXNlIFN0dWRpZXMgVHV0b3JpYWwKY3NzOiB3d3cvc3R5bGUuY3NzCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgaW5jbHVkZXM6CiAgICAgICBpbl9oZWFkZXI6IHd3dy9HQV9TY3JpcHQuUmh0bWwKICAgIHNlbGZfY29udGFpbmVkOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwpydW50aW1lOiBzaGlueV9wcmVyZW5kZXJlZAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBvdXQud2lkdGggPSAnOTAlJykKbGlicmFyeShrbml0cikKbGlicmFyeShoZXJlKQoKIyBhZGRpdGlvbmFsIGxpYnJhcmllcyBuZWVkZWQKbGlicmFyeShsZWFybnIpCmxpYnJhcnkoZ3JhZGV0aGlzKQpncmFkZXRoaXM6OmdyYWRldGhpc19zZXR1cCgpCmBgYAoKPCEtLSBPcGVuIGFsbCBsaW5rcyBpbiBuZXcgdGFiLS0+ICAKPGJhc2UgdGFyZ2V0PSJfYmxhbmsiLz4gCgo8cD4mbmJzcDs8L3A+CgojICoqMS4gU2V0dGluZyBVcCoqCioqKgoKIyMgKipgd3d3YCBEaXJlY3RvcnkqKgoqKioKCk9ubHkgdGhlIGZpbGVzIGluIHRoaXMgYHd3d2AgZGlyZWN0b3J5IHdpbGwgYmUgcHVibGlzaGVkIHdpdGggdGhlIGBpbmRleC5SbWRgLgoKSW4gdGhpcyBgd3d3YCBkaXJlY3RvcnksIHdlIG5lZWQgdG8gaGF2ZToKCiogYHN0eWxlLmNzc2AKKiBgR0FfU2NyaXB0LlJodG1sYAoqICBtb3ZlIHRoZSBgZGF0YWAsIGBkb2NzYCwgYGltZ2AsIGV0Yy4gZGlyZWN0b3JpZXMgb2YgdGhlIHN0YXRpYyB2ZXJzaW9uIGludG8gdGhlIGB3d3dgIGRpcmVjdG9yeS4gVGhlc2UgZGlyZWN0b3JpZXMgY29udGFpbiB0aGUgZmlsZXMgbmVlZGVkIHRvIHJlbmRlciB0aGUgYGluZGV4LlJtZGAgZmlsZS4KKiBBZGRpdGlvbmFsbHksIHdlIG5lZWQgdG8gbWFrZSBhbiAqKmBleGVyY2lzZWAgc3ViLWRpcmVjdG9yeSoqLiBUaGlzIGlzIHdoZXJlIHdlIHdvdWxkIHB1dCB0aGUgYC5yZGFgIGZpbGVzIGZvciB0aGUgInNldHVwIiBvZiB0aGUgZXhlcmNpc2VzLgoKIyMgKipZQU1MIEhlYWRlcioqCioqKgoKUmVmZXIgdG8gdGhlIFlBTUwgaGVhZGVyIG9mIHRoaXMgYC5SbWRgIGZpbGUuCgpJbXBvcnRhbnQgbm90ZXMgKHRoZSBmb2xsb3dpbmdzIGFyZSBkaWZmZXJlbnQgZnJvbSB0aGUgc3RhdGljIHZlcnNpb24pOgoKKiB0aXRsZQoqIGBjc3M6IHd3dy9zdHlsZS5jc3NgICh0aGUgc3RhdGljcyB2ZXJzaW9uIGRvZXMgbm90IGhhdmUgdGhlIGB3d3dgIGRpcmVjdG9yeSkKKiBgaW5faGVhZGVyOiB3d3cvR0FfU2NyaXB0LlJodG1sYCAodGhlIHN0YXRpY3MgdmVyc2lvbiBkb2VzIG5vdCBoYXZlIHRoZSBgd3d3YCBkaXJlY3RvcnkpCiogdGhlIGFkZGl0aW9uIG9mIGBydW50aW1lOiBzaGlueV9wcmVyZW5kZXJlZGAKCiMjICoqUiBTZXR1cCBDaHVuayoqCioqKgoKUmVmZXIgdG8gdGhlIHNldHVwIGNodW5rIG9mIHRoaXMgYC5SbWRgIGZpbGUuCgpUaGUgbWFpbiBkaWZmZXJlbmNlIGhlcmUgaXMgdGhlIGFkZGl0aW9uIG9mIHRoZSB0aGUgZm9sbG93aW5nIGxpYnJhcmllczoKCmBgYHtyLCBldmFsPUZBTFNFfQpsaWJyYXJ5KGxlYXJucikKbGlicmFyeShncmFkZXRoaXMpCmdyYWRldGhpczo6Z3JhZGV0aGlzX3NldHVwKCkKYGBgCgoqTm90ZTogeW91IG1pZ2h0IG5lZWQgdG8gaW5zdGFsbCBgZ3JhZGV0aGlzYCBmcm9tIFtnaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL2dyYWRldGhpcykqCgojIyAqKlRyYW5zbGF0ZSoqCioqKgoKVXNlIHRoZSBmb2xsb3dpbmcgY29kZSBmb3IgdHJhbnNsYXRpb24KCmBgYAo8ZGl2IGFsaWduPSJsZWZ0IiBpZD0iZ29vZ2xlX3RyYW5zbGF0ZV9lbGVtZW50Iiw+PC9kaXY+Cgo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPScvL3RyYW5zbGF0ZS5nb29nbGUuY29tL3RyYW5zbGF0ZV9hL2VsZW1lbnQuanM/Y2I9Z29vZ2xlVHJhbnNsYXRlRWxlbWVudEluaXQnPjwvc2NyaXB0PgoKPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPgpmdW5jdGlvbiBnb29nbGVUcmFuc2xhdGVFbGVtZW50SW5pdCgpIHsKICBuZXcgZ29vZ2xlLnRyYW5zbGF0ZS5UcmFuc2xhdGVFbGVtZW50KHtwYWdlTGFuZ3VhZ2U6ICdlbid9LCAnZ29vZ2xlX3RyYW5zbGF0ZV9lbGVtZW50Jyk7Cn0KPC9zY3JpcHQ+CmBgYAoKKk5vdGU6IHRoaXMgaXMgZGlmZmVyZW50IGZyb20gdGhlIHN0YXRpY3MgdmVyc2lvbi4gVGhlcmUgaXMgYW4gZXh0cmEgImNvbW1hIiBhdCB0aGUgZW5kIG9mIGBpZD0iZ29vZ2xlX3RyYW5zbGF0ZV9lbGVtZW50ImAuIFRoZSB0cmFuc2xhdGlvbiB0b29sIHdvdWxkIG5vdCB3b3JrIHdpdGhvdXQgdGhpcyBjb21tYSAobm90IHN1cmUgd2h5KS4qCgojIyAqKlRhYmxlIG9mIENvbnRlbnQqKgoqKioKCllvdSBtaWdodCB3YW50IHRvIGdldCByaWQgb2YgdGhlIGZvbGxvd2luZyBjc3MgY29kZSBmcm9tIHRoZSBzdGF0aWMgdmVyc2lvbgoKYGBgCjxzdHlsZT4KI1RPQyB7CiAgYmFja2dyb3VuZDogdXJsKCJodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vaW1nL2ljb24tYmFoaS5wbmciKTsKICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47CiAgcGFkZGluZy10b3A6IDI0MHB4ICFpbXBvcnRhbnQ7CiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsKfQo8L3N0eWxlPgpgYGAKClVubGlrZSBpbiB0aGUgc3RhdGljIHZlcnNpb24sIHRoaXMgd291bGQgbm90IGFkZCB0aGUgbG9nbyB0byB0aGUgdGFibGUgb2YgY29udGVudCBpbiB0aGUgaW50ZXJhY3RpdmUgYXBwLiBDb3VsZCB3b3JrIG9uIGhvdyB0byBhZGQgbG9nbyB0byB0aGUgdG9jIGZvciBpbnRlcmFjdGl2ZSBhcHBzLgoKIyMgKipPcHRpb25hbDogQWRkIGBleGVyY2lzZV9ibG9ja2AgdG8gYHd3dy9zdHlsZS5jc3NgKioKKioqCgpZb3UgY291bGQgYWRkIGEgc3BlY2lmaWMgc3R5bGUgZm9yIHRoZSBleGVyY2lzZXMgYnkgYWRkaW5nIHRoZSBmb2xsb3dpbmcgY29kZSB0byB0aGUgYHN0eWxlLmNzc2AgZmlsZToKCmBgYAouZXhlcmNpc2VfYmxvY2sgewogICAgcGFkZGluZzogLjVlbTsKICAgIGJvcmRlcjogMXB4IHNvbGlkIGxpZ2h0Z3JleTsKICAgIGJhY2tncm91bmQ6IHdoaXRlOwogICAgY29sb3I6IGJsYWNrOwp9CmBgYAoKIyMjIyB7LmV4ZXJjaXNlX2Jsb2NrfQoKVGhpcyBpcyB3aGF0IHRoZSBleGVyY2lzZSBibG9jayBsb29rcyBsaWtlLiBZb3UgbWlnaHQgbW9kaWZ5IGl0IGlmIHlvdSB3YW50LgoKIyMjIwoKCiMgKioyLiBNb2RpZmljYXRpb25zIG9mIHRoZSBTdGF0aWMgVmVyc2lvbioqCioqKgoKIyMgKipgZGF0YWAsIGBkb2NzYCwgYGltZ2AsIGV0Yy4gRGlyZWN0b3JpZXMgYXJlIG5vdyBTdWItRGlyZWN0b3JpZXMgb2YgYHd3d2AqKgoqKioKClRoZSBmaWxlIHBhdGhzIGluIHRoZSBjYXNlIHN0dWR5IGluZGV4LlJtZCBmaWxlIHRoYXQgcmVmZXIgdG8gdGhlc2UgZGlyZWN0b3JpZXMgd2lsbCBuZWVkIHRvIGJlIGVkaXRlZCB0byByZWZsZWN0IHRoZSBuZXcgcGFyZW50IGRpcmVjdG9yeSBgd3d3YC4gVGhlcmUgYXJlIHR3byBjYXNlcyBvZiBjb2RlIGNodW5rcyB0aGF0IHdpbGwgbmVlZCB0byBiZSBlZGl0ZWQgc2xpZ2h0bHkgZGlmZmVyZW50bHkuIEkgd2lsbCB1c2Ugc29tZSBleGFtcGxlcyB0byBleHBsYWluIHRoaXMuICoqQSBxdWljayB3YXkgdG8gZmluZCB3aGVyZSBuZWVkcyB0byBiZSBtb2RpZmllZCBpcyB0byBkbyBgQ1RSTCArIEZgIGFuZCBzZWFyY2ggZm9yIGBoZXJlKGAqKgoKIyMjIENhc2UgMTogU3RhdGljIHZlcnNpb24gY2h1bmsgc2V0IHRvIGBlY2hvID0gRkFMU0VgCgoqKioKKldoZW4gdGhlIHN0YXRpYyB2ZXJzaW9uIGhhcyBgZWNobyA9IEZBTFNFYDoqCgohW10od3d3L2ltZy9pbmNsdWRlZ3JhcGhpY3MuUE5HKQoKKioqCgoqU2ltcGx5IGFkZCB0aGUgYHd3d2AgZGlyZWN0b3J5IHRvIHRoZSBpbnRlcmFjdGl2ZSB2ZXJzaW9uOioKCiFbXSh3d3cvaW1nL2luY2x1ZGVncmFwaGljc19uZXcuUE5HKQoKKioqCgojIyMgQ2FzZSAyOiBTdGF0aWMgdmVyc2lvbiBjaHVuayBub3Qgc2V0IHRvIGBlY2hvID0gRkFMU0VgCioqKgoKKldoZW4gdGhlIHN0YXRpYyB2ZXJzaW9uIGRvZXMgbm90IGhhdmUgYGVjaG8gPSBGQUxTRWA6KgoKIVtdKHd3dy9pbWcvbG9hZC5QTkcpCgoqKioKCipTZXQgdGhlIG9yaWdpbmFsIGNodW5rIHRvIGBldmFsID0gRkFMU0VgIGFuZCB0aGUgbmV3IGNodW5rIHRvIGBlY2hvID0gRkFMU0VgIGluIHRoZSBpbnRlcmFjdGl2ZSB2ZXJzaW9uOioKCiFbXSh3d3cvaW1nL2xvYWRfbmV3LlBORykKCioqKgoKCiMgKiozLiBBZGQgRXhlcmNpc2VzKioKKioqCgpFYWNoIGV4ZXJjaXNlIGNodW5rIHNob3VsZCBoYXZlIHRoZWlyIG93biBuYW1lLiBGb3IgZXhhbXBsZSwgYGR3X2NvZGUxYCBmb3IgdGhlIGZpcnN0IGNvZGluZyBwcm9ibGVtIGVtYmVkZGVkIGluIHRoZSBhbmFseXNpcyBvZiB0aGUgIkRhdGEgV3JhbmdsaW5nIiBzZWN0aW9uLCBgZHdfcXVpemAgZm9yIHRoZSBxdWl6IG9mIHRoZSAiRGF0YSBXcmFuZ2xpbmciIHNlY3Rpb24sIGBkdl9leGVyY2lzZTFgIGZvciB0aGUgZmlyc3QgY29kaW5nIGV4ZXJjaXNlIG9mIHRoZSAiRXhlcmNpc2UiIHN1YnNlY3Rpb24gb2YgdGhlICJEYXRhIFZpc3VhbGl6YXRpb24iIHNlY3Rpb24sIGV0Yy4KCiMjICoqQ29kaW5nIFByb2JsZW1zIEVtYmVkZGVkIGluIHRoZSBBbmFseXNlcyoqCioqKgoKVGhlc2UgY291bGQgYmUgdGhlICJRdWVzdGlvbiBPcHBvcnR1bml0aWVzIiAsb3Igd2hlbiBhbiBhbmFseXNpcyBpcyByZXBlYXRlZCB3aXRoIGEgZGlmZmVyZW50IGRhdGFzZXQgYW5kIHdlIHdhbnQgdGhlIHN0dWRlbnRzIHRvIGNvbWUgdXAgd2l0aCB0aGUgY29kZSB1c2luZyB3aGF0IHRoZXkgbGVhcm5lZCwgZXRjLgoKKiBGaXJzdCwgYmVmb3JlIHRoZSBleGVyY2lzZSBzZXR1cCBjaHVuaywgd2UgbmVlZCB0byBzYXZlIHRoZSBkYXRhc2V0IG5lZWRlZCBpbiB0aGUgZXhlcmNpc2UgYXMgYSBgLnJkYWAgZmlsZSBhbmQgcHV0IGl0IGluIHRoZSBgZXhlcmNpc2VgIHN1Yi1kaXJlY3Rvcnkgb2YgdGhlIGB3d3dgIGZvbGRlci4KKiBUaGVuLCBpbiB0aGUgZXhlcmNpc2Ugc2V0dXAgY2h1bmssIHdlIG5lZWQgdG8gbG9hZCB3aGF0ZXZlciBsaWJyYXJpZXMgbmVlZGVkIGZvciB0aGlzIGV4ZXJjaXNlIHRoYXQgYXJlIG5vdCBsb2FkZWQgaW4gdGhlIGBpbmRleC5SbWRgIHNldHVwIGNodW5rLiBJbiBhZGRpdGlvbiwgd2UgbmVlZCB0byBsb2FkIHRoZSBgLnJkYWAgbWFkZSBpbiB0aGUgZmlyc3Qgc3RlcC4KKiBUaGVuLCB3ZSBjYW4gc3RhcnQgbWFraW5nIHRoZSBleGVyY2lzZS4KKiBGaW5hbGx5LCB3aGVuIG5lY2Vzc2FyeSwgYWZ0ZXIgdGhlIGV4ZXJjaXNlLCB3ZSBjYW4gbWFrZSBhIGNsaWNrIHRvIGV4cGVuZCBzZWN0aW9uIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIHRoZSBvdXRwdXQgc28gdGhhdCBzdHVkZW50cyBtYXkgY2hvb3NlIHRvIHNraXAgdGhlc2UgZXhlcmNpc2VzLgoKSGVyZSBpcyBhbiBleGFtcGxlIGZyb20gdGhlIG9iZXNpdHkgY2FzZSBzdHVkeToKCiFbXSh3d3cvaW1nL2V4ZXJjaXNlMS5QTkcpCgohW10od3d3L2ltZy9leGVyY2lzZTIuUE5HKQoKCiMjICoqVGhlIEV4ZXJjaXNlIFN1YnNlY3Rpb24qKgoqKioKCkVhY2ggc2VjdGlvbiAoZGF0YSB3cmFuZ2xpbmcsIGRhdGEgdmlzdWFsaXphdGlvbiwgZXRjLikgY291bGQgaGF2ZSB0aGVpciAiRXhlcmNpc2UiIHN1YnNlY3Rpb24gYXMgdGhlIGxhc3Qgc3Vic2VjdGlvbi4KCiMjIyAqKlF1aXp6ZXMqKgoqKioKCkZvbGxvd2luZyBpcyBhbiBleGFtcGxlIGZyb20gdGhlIENPMiBjYXNlIHN0dWR5OgoKYGBge3IgZHdfcXVpeiwgZWNobyA9IEZBTFNFfQpxdWl6KGNhcHRpb24gPSAiIiwKICBxdWVzdGlvbigiV2hpY2ggb25lIG9mIHRoZSBmb2xsb3dpbmcgZnVuY3Rpb25zIGluIHRoZSBgZHBseXJgIHBhY2thZ2UgYWxsb3dzIHVzIHRvIHNlZSBhbGwgb2YgdGhlIHZhcmlhYmxlcyAoY29sdW1ucykgYXQgb25jZSwgd2hlcmUgc2V2ZXJhbCB2YWx1ZXMgb2YgdGhvc2UgY29sdW1ucyBhcmUgc2hvd24gb24gdGhlIHJpZ2h0IG9mIHRoZSB2YXJpYWJsZSBuYW1lcz8iLAogICAgYW5zd2VyKCJgc2xpY2VfaGVhZCgpYCIsIG1lc3NhZ2UgPSAiVGhpcyBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gc2VlIGp1c3QgdGhlIGZpcnN0IHJvd3Mgb2YgdGhlIGRhdGEuIiksCiAgICBhbnN3ZXIoImBzbGljZV9zYW1wbGUoKWAiLCBtZXNzYWdlID0gIlRoaXMgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIHNlZSBhIHNlbGVjdGlvbiBvZiByYW5kb20gcm93cyBvZiB0aGUgZGF0YS4iKSwKICAgIGFuc3dlcigiYHNsaWNlX3RhaWwoKWAiLCBtZXNzYWdlID0gIlRoaXMgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIHNlZSB0aGUgcm93cyBhdCB0aGUgZW5kIG9mIHRoZSBkYXRhLiIpLAogICAgYW5zd2VyKCJgZ2xpbXBzZSgpYCIsIGNvcnJlY3QgPSBUUlVFKSwKICAgIGFsbG93X3JldHJ5ID0gVFJVRSwKICAgIHJhbmRvbV9hbnN3ZXJfb3JkZXIgPSBUUlVFCiAgKSwKICBxdWVzdGlvbigiV2hpY2ggb25lIG9mIHRoZSBwaXBlIG9wZXJhdG9ycyAoZnJvbSB0aGUgYG1hZ3JpdHRyYCBwYWNrYWdlKSBzaG91bGQgYmUgdXNlZCByaWdodCBhZnRlciBhIHZhcmlhYmxlIG5hbWUgaWYgd2Ugd2FudCB0byBwZXJmb3JtIGEgc2VxdWVuY2Ugb2Ygb3BlcmF0aW9ucyBvbiB0aGF0IHZhcmlhYmxlLCBhbmQgbWVhbndoaWxlLCBhc3NpZ24gdGhlIGZpbmFsIG91dHB1dCB0byB0aGF0IHZhcmlhYmxlICh3aXRob3V0IHJlZGVmaW5pbmcgdGhhdCB2YXJpYWJsZSB1c2luZyBgPC1gIG9yIGA9YCk/IiwKICAgIGFuc3dlcigiYCU+JWAiLCBtZXNzYWdlID0gIlRoaXMgb3BlcmF0b3IgY2Fubm90IGFzc2lnbiB0aGUgZmluYWwgb3V0cHV0IHRvIHRoYXQgdmFyaWFibGUuIiksCiAgICBhbnN3ZXIoImAlPCVgIiwgbWVzc2FnZSA9ICJUaGlzIGlzIG5vdCBhIHZhbGllIHBpcGUgb3BlcmF0b3IuIiksCiAgICBhbnN3ZXIoImAlVD4lYCIsIG1lc3NhZ2UgPSAiVGhpcyBpcyB0aGUgc2lkZS1lZmZlY3RzIG9wZXJhdG9yLiIpLAogICAgYW5zd2VyKCJgJTw+JWAiLCBjb3JyZWN0ID0gVFJVRSksCiAgICBhbGxvd19yZXRyeSA9IFRSVUUsCiAgICByYW5kb21fYW5zd2VyX29yZGVyID0gVFJVRQogICksCiAgcXVlc3Rpb24oIldoaWNoIG9mIHRoZSBmb2xsb3dpbmcgY2FuIHRoZSBgbXV0YXRlKClgIGZ1bmN0aW9uIGluIHRoZSBgZHBseXJgIHBhY2thZ2UgZG8/IChtb3JlIHRoYW4gb25lIGNvcnJlY3QgYW5zd2VycykiLAogICAgYW5zd2VyKCJTZWxlY3QgY2VydGFpbiB2YXJpYWJsZXMoY29sdW1ucykgb2YgdGhlIGRhdGEuIiwgbWVzc2FnZSA9ICJTZWxlY3RpbmcgY2VydGFpbiB2YXJpYWJsZXMoY29sdW1ucykgb2YgdGhlIGRhdGEgaXMgdGhlIGZ1bmN0aW9uIG9mIHRoZSBgc2VsZWN0KClgIGZ1bmN0aW9uLiIpLAogICAgYW5zd2VyKCJSZW5hbWUgYSB2YXJpYWJsZS4iLCBtZXNzYWdlID0gIlJlbmFtaW5nIGEgdmFyaWFibGUgaXMgdGhlIGZ1bmN0aW9uIG9mIHRoZSBgcmVuYW1lKClgIGZ1bmN0aW9uLiIpLAogICAgYW5zd2VyKCJDcmVhdGUgYSBuZXcgdmFyaWFibGUuIiwgY29ycmVjdCA9IFRSVUUpLAogICAgYW5zd2VyKCJNb2RpZnkgYW4gZXhpc3RpbmcgdmFyaWFibGUuIiwgY29ycmVjdCA9IFRSVUUpLAogICAgYWxsb3dfcmV0cnkgPSBUUlVFLAogICAgcmFuZG9tX2Fuc3dlcl9vcmRlciA9IFRSVUUKICApCikKYGBgCgojIyMgKipDb2RpbmcgRXhlcmNpc2UqKgoqKioKCiogRm9sbG93aW5nIGlzIGFuIGV4YW1wbGUgZnJvbSB0aGUgQ08yIGNhc2Ugc3R1ZHkgKip3aXRob3V0IHVzZSBvZiB0aGUgYGdyYWRldGhpc2AgcGFja2FnZSoqOgoKIyMjIyB7LmV4ZXJjaXNlX2Jsb2NrfQoKV2UgaGF2ZSBjcmVhdGVkIGEgZGF0YXNldCBjYWxsZWQgYHdpZGVfZm9ybWF0YCB0aGF0IGlzIGluICJ3aWRlIiBmb3JtYXQuIFdyaXRlIHNvbWUgY29kZSB0byBjb252ZXJ0IGl0IHRvICJsb25nIiBmb3JtYXQuIChXZSB3YW50IDMgY29sdW1ucyB3aXRoIG5hbWVzICJJRCIsICJWYXJpYWJsZSIsIGFuZCAiVmFsdWUiLikKCmBgYHtyIGR3X2V4ZXJjaXNlMS1zZXR1cH0KSUQgPC0gYygxLCAyLCAzKQpZZWFyIDwtIGMoMjAxNSwgMjAxOCwgMjAxOSkKTGVuZ3RoIDwtIGMoMjAsIDIxLjUsIDE5KQp3aWRlX2Zvcm1hdCA8LSBkYXRhLmZyYW1lKElELCBZZWFyLCBMZW5ndGgpCmBgYAoKYGBge3IgZHdfZXhlcmNpc2UxLCBleGVyY2lzZT1UUlVFLCBleGVyY2lzZS5ldmFsPVRSVUUsIGV4ZXJjaXNlLmxpbmVzID0gNX0Kd2lkZV9mb3JtYXQKYGBgCgpgYGB7ciBkd19leGVyY2lzZTEtaGludH0Kd2lkZV9mb3JtYXQgJT4lCiAgcGl2b3RfbG9uZ2VyKCkKYGBgCgpgYGB7ciBkd19leGVyY2lzZTEtc29sdXRpb259CndpZGVfZm9ybWF0ICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLUlELCBuYW1lc190byA9ICJWYXJpYWJsZSIsIHZhbHVlc190byA9ICJWYWx1ZSIpCmBgYAoKIyMjIwoKPHA+Jm5ic3A7PC9wPgoKKiBGb2xsb3dpbmcgaXMgYW4gZXhhbXBsZSBmcm9tIHRoZSBDTzIgY2FzZSBzdHVkeSAqKndpdGggdXNlIG9mIHRoZSBgZ3JhZGV0aGlzYCBwYWNrYWdlKio6CgojIyMjIHsuZXhlcmNpc2VfYmxvY2t9CgpgbXRjYXJzYCBpcyBhIGJ1aWx0LWluIFIgZGF0YXNldCBhcyBzaG93biBiZWxvdy4gVXNlIHRoaXMgZGF0YXNldCB0byBjb21wbGV0ZSB0aGUgZm9sbG93aW5nIGV4ZXJjaXNlLgoKYGBge3J9Cm10Y2FycwpgYGAKCldyaXRlIHNvbWUgY29kZSB0aGF0IHdpbGw6CgoxLiBDcmVhdGUgYSBuZXcgZGF0YXNldCBjYWxsZWQgYG5ldy5tdGNhcnNgIGZyb20gYG10Y2Fyc2AuCjIuIENyZWF0ZSBhIG5ldyBjb2x1bW4gY2FsbGVkIGBjYXJgIGluIGBuZXcubXRjYXJzYCB0aGF0IHVzZXMgdGhlIHZhbHVlcyBmcm9tIHRoZSByb3cgbmFtZXMgb2YgYG10Y2Fyc2AuIChVc2UgdGhlIGByb3duYW1lc190b19jb2x1bW5gIGZ1bmN0aW9uIGZyb20gdGhlIGB0aWJibGVgIHBhY2thZ2UuIFNlZSBkb2N1bWVudGF0aW9uIFtoZXJlXShodHRwczovL3RpYmJsZS50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9yb3duYW1lcy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9LikKMy4gT25seSBrZWVwIHRoZSBgY2FyYCwgYG1wZ2AsIGFuZCBgY3lsYCBjb2x1bW5zIG9mIHRoaXMgYG5ldy5tdGNhcnNgIGRhdGFzZXQuCjQuIE9ubHkga2VlcCB0aGUgY2FycyB0aGF0IGhhdmUgYGN5bGAgPSA0Lgo1LiBSZWFycmFuZ2UgdGhlIGRhdGFzZXQgYnkgYG1wZ2AgaW4gZGVzY2VuZGluZyBvcmRlci4KCipOb3RlOiByZXBsYWNlIHRoZSB1bmRlcnNjb3JlcygiXF8iKSB3aXRoIHlvdXIgY29kZSB3aXRoIG9uZSBjaGFyYWN0ZXIgcGVyICJcXyIuIENsaWNrICJTdWJtaXQgQW5zd2VyIiB0byBjaGVjayB5b3VyIGFuc3dlci4gKgoKYGBge3IgZHdfZXhlcmNpc2UyLXNldHVwfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgpgYGB7ciBkd19leGVyY2lzZTIsIGV4ZXJjaXNlPVRSVUUsIGV2YWw9RkFMU0V9CiMgc3RlcCAxCm5ldy5tdGNhcnMgPC0gbXRjYXJzICU+JQogICMgc3RlcCAyCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJfX18iKSAlPiUKICAjIHN0ZXAgMwogIF9fX19fXyhfX18sIF9fXywgX19fKSAlPiUKICAjIHN0ZXAgNAogIF9fX19fXyhfX18gPT0gXykgJT4lCiAgIyBzdGVwIDUKICBfX19fX19fKF9fX18obXBnKSkKCiMgdmlldyBkYXRhIChEbyBOT1QgaW5jbHVkZSB0aGlzIHBhcnQgd2hlbiBzdWJtaXR0aW5nIHlvdXIgYW5zd2VyISkKIyBuZXcubXRjYXJzCmBgYAoKYGBge3IgZHdfZXhlcmNpc2UyLWhpbnQtMX0KIyBzdGVwIDI6CiMgVGhlICJ2YXIiIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSBuZXcgY29sdW1uIHRoYXQgd2lsbCB1c2UgdGhlIHZhbHVlcyBmcm9tIHRoZSByb3cgbmFtZXMuIFdoYXQgaXMgdGhlIGNvbHVtbiBuYW1lPwpgYGAKCmBgYHtyIGR3X2V4ZXJjaXNlMi1oaW50LTJ9CiMgc3RlcCAyOgojIFRoZSAidmFyIiBhcmd1bWVudCBpcyB0aGUgbmFtZSBvZiB0aGUgbmV3IGNvbHVtbiB0aGF0IHdpbGwgdXNlIHRoZSB2YWx1ZXMgZnJvbSB0aGUgcm93IG5hbWVzLiBXaGF0IGlzIHRoZSBjb2x1bW4gbmFtZT8KCiMgc3RlcCAzOgojIFdoaWNoIGZ1bmN0aW9uIG9mIHRoZSAiZHBseXIiIHBhY2thZ2Ugc2VsZWN0IGNvbHVtbnM/CmBgYAoKYGBge3IgZHdfZXhlcmNpc2UyLWhpbnQtM30KIyBzdGVwIDI6CiMgVGhlICJ2YXIiIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSBuZXcgY29sdW1uIHRoYXQgd2lsbCB1c2UgdGhlIHZhbHVlcyBmcm9tIHRoZSByb3cgbmFtZXMuIFdoYXQgaXMgdGhlIGNvbHVtbiBuYW1lPwoKIyBzdGVwIDM6CiMgV2hpY2ggZnVuY3Rpb24gb2YgdGhlICJkcGx5ciIgcGFja2FnZSBzZWxlY3QgY29sdW1ucz8KCiMgc3RlcCA0OgojIFdoaWNoIGZ1bmN0aW9uIG9mIHRoZSAiZHBseXIiIHBhY2thZ2Ugc3Vic2V0IHJvd3M/CmBgYAoKYGBge3IgZHdfZXhlcmNpc2UyLWhpbnQtNH0KIyBzdGVwIDI6CiMgVGhlICJ2YXIiIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSBuZXcgY29sdW1uIHRoYXQgd2lsbCB1c2UgdGhlIHZhbHVlcyBmcm9tIHRoZSByb3cgbmFtZXMuIFdoYXQgaXMgdGhlIGNvbHVtbiBuYW1lPwoKIyBzdGVwIDM6CiMgV2hpY2ggZnVuY3Rpb24gb2YgdGhlICJkcGx5ciIgcGFja2FnZSBzZWxlY3QgY29sdW1ucz8KCiMgc3RlcCA0OgojIFdoaWNoIGZ1bmN0aW9uIG9mIHRoZSAiZHBseXIiIHBhY2thZ2Ugc3Vic2V0IHJvd3M/CgojIHN0ZXAgNToKIyBXaGljaCBmdW5jdGlvbiBvZiB0aGUgImRwbHlyIiBwYWNrYWdlIHdpbGwgcmVvcmRlciB0aGUgZGF0YT8KIyBXaGF0IGFyZ3VtZW50IGRvIHdlIG5lZWQgdG8gcmVvcmRlciBpbiBkZXNjZW5kaW5nIG9yZGVyPwpgYGAKCmBgYHtyIGR3X2V4ZXJjaXNlMi1oaW50LTV9CiMgTmV4dCBoaW50IHdpbGwgc2hvdyB5b3UgdGhlIHNvbHV0aW9uCmBgYAoKYGBge3IgZHdfZXhlcmNpc2UyLXNvbHV0aW9ufQpuZXcubXRjYXJzIDwtIG10Y2FycyAlPiUKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNhciIpICU+JQogIHNlbGVjdChjYXIsIG1wZywgY3lsKSAlPiUKICBmaWx0ZXIoY3lsID09IDQpICU+JQogIGFycmFuZ2UoZGVzYyhtcGcpKQpgYGAKCmBgYHtyIGR3X2V4ZXJjaXNlMi1jaGVjaywgZXZhbD1GQUxTRX0KZ3JhZGVfY29kZSgpCmBgYAoKIyMjIwoKCiMgKio0LiBNYWludGVuYW5jZSBOb3RlcyoqCioqKgoKU2VlIHRoZSBgbWFpbnRlbmFuY2Vfbm90ZXMuUm1kYCBmaWxlIGFzIGFuIGV4YW1wbGUuCgpNYWtlIHN1cmUgdG8gbGlzdCB0aGUgbmFtZXMgb2YgdGhlIGV4ZXJjaXNlIGNodW5rcyBmb3IgZnV0dXJlIG1haW50ZW5hbmNlLiBFeGNlcHQgZm9yIHRoaW5ncyBtZW50aW9uZWQgaW4gdGhpcyB0dXRvcmlhbCwgb3RoZXIgY2hhbmdlcyBzaG91bGQgYmUgbm90ZWQgYXMgd2VsbC4KCiFbXSh3d3cvaW1nL21haW50ZW5hbmNlLlBORykKCiMgKio1LiBQdWJsaXNoaW5nKioKKioqCgpNYWtlIHN1cmUgdGhlIGByc2Nvbm5lY3RgIGZvbGRlciBpcyBhbHNvIHB1c2hlZCB0byBHaXRIdWIu