First Steps in R

In order to follow along with this session, you’ll need to have downloaded some of the files in the OSF repo for this series. If you haven’t done so, go to this page and select the “Download this folder” button on the top right of the screen: download OSF files

If you have any issues, please ask your instructor, or refer to “Block 1: Introduction to OSF”.

Introduction

Now that we’ve familiarized ourselves a bit with R and RStudio, we can start moving forward to working with data in R, which is where the real fun begins!

R Projects

Setting working directory

When we talked about relative file paths in the previous session, it was revolving around this idea of where you are in the file system. In a coding environment, this translates to the idea of setting a working directory, which is a way of telling R (or other coding languages) where you want to be in your computer’s file system when you’re doing your work.

A common way to set a working directory is to use the setwd() function. This function manually sets the working directory during an R session. It tells R where to look for files and where to save outputs just for that session.

This can be done in 2 ways:

  • Manually in R, by writing setwd("path-to-director/secondary-part/etc...")
  • Setting it by selecting the Session tab in the toolbar, and selecting Set Working Directory:

But here’s the problem…

Using setwd() can break your code when:

  • Someone else tries to run it on their machine.
  • You move your project folder.
  • You’re running your code on a server or in cloud environments like RStudio Cloud.

Since file paths are hardcoded and depend on your machine, it’s not reproducible.

Create an R Project

An R Project is a feature in RStudio (and supported in base R too) that provides a self-contained working environment. When you create an R Project it creates a .Rproj file in a folder and that folder becomes the root directory of your project. Every time you open the project (via the .Rproj file), R automatically sets the working directory to that folder. You can reference files relative to the project root — no need to hardcode file paths.

This is super useful when you’re working on multiple analyses, sharing code with collaborators, or version-controlling with Git. It is a good practice for reproducible research

To create an R Project, select File > New Project

Your Turn!

Create your first RProject. Let’s figure out what we should call it!

Packages and Libraries

When you first download R, it comes equipped with a number of pre-installed functions, or capabilities, that you can start using immediately. This is often called “Base R:. However, for certain tasks and workflows, it can be beneficial to use more specialized tools, or functions, to accomplish work and facilitate workflows for efficiently. This is where packages and libraries come into play.

  • Packages: Packages are an extension of the pre-built functions in R, and can be installed to bring in specific functions to accomplish tasks, bring in sample datasets to play with, among other things. There are tons of R packages out there, but here is a list of some of the most common/useful ones: Quick list of useful R packages

  • Libraries: Once you have installed a package, they are stored as libraries in R. You only have to install them once, and anytime you want to use the package you can use the library() function, which is described below.

Tidyverse

As mentioned in the session “Reproducible Research: Moving From Excel to Scripting”, we will be using an R package called the “Tidyverse”. The Tidyverse is a very commonly used package for research and data science activities, and instead of being a single package, it is a collection of packages that are designed to work together and which focus on the connections between activities in the data science workflow. Each package follows the same syntax, which makes learning them easier, and the website functions as a really good reference point if you’re struggling with how to approach a specific task.

Let’s take a closer look! Tidyverse


Let’s get started!

First, let’s create a new R script.

To create an R script file, select File > New File > R Script

Install Package

To install a package we use the function install.packages().

#install.packages("tidyverse")

Load Libraries

Packages are stored in libraries. Once a package is installed, we need to call the library with the function library().

library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.5.1

Note that the package name needs to be in quotations when installing the package, but not when loading the library.

Because packages only need to be installed once, we can do this in the R console as opposed to in the script.

Because libraries need to be loaded in each working session, we can do this in the R script so that others can see what libraries we are using and need to be loaded.

Referring again to the Tidyverse Data Science Workflow, in this session we’ll be focusing on the first two steps:

Source

Reading Data

In order to start working with a dataset in R, we first need to import, or “read in”, the data. As mentioned in the session “Reproducible Research: Moving From Excel to Scripting”, we will be working with .csv files, but R is capable of reading in other file types as well.

Read a csv file

To import a csv file we can use the read_csv() function and assign it to a new object we will call js_data. We create a new object to be able to call it in different functions later on.

js_data <- read_csv("data/block-4_first-steps.csv")

Read Other Formats

In the example we are working with the data is stored in a csv file. The package readr from Tidyverse can also read other formats like read_tsv()(tab-separated values), read_delim()(delimited files CSV and TSV), read_table()(whitespace-separated files), read_log()(web log files).

There are other functions and packages that allow us to import different file types.

File Type Function Package
.csv read_csv() readr
.xlsx read.xlsx() xlsx
.sav read_sav() haven
.sas7bdat , .sas7bcat read_sas() haven
.dta read_dta() haven

Listing Column Names

To ask for a list of all the column names in our dataset we can use the names() function.

names(js_data)
##  [1] "PUMFID"   "AGEGR10"  "SEX"      "MARSTAT"  "PRV"      "LUC_RST"  "EHG_ALL"  "GTU_110"  "GTU_130" 
## [10] "DUR01"    "DUR05"    "DUR06"    "DURS200"  "DURL313"  "DUR08"    "DUR13"    "DUR14"    "DUR15"   
## [19] "MRW_20"   "MRW_30"   "MRW_40"   "MRW_D40A" "MRW_D40B" "EDM_02"   "TST_01"   "TCS_110"  "TCS_120" 
## [28] "TCS_150"  "TCS_200"

Notice that the column names from the original dataset don’t provide a clear description of what the variable is. We will change the column names later to facilitate working with our data in the future.

Head Function

The head function will display the top rows of the dataset. It will include information about the default data type assigned to each column. We will cover data types more in the next session.

head(js_data)
PUMFID AGEGR10 SEX MARSTAT PRV LUC_RST EHG_ALL GTU_110 GTU_130 DUR01 DUR05 DUR06 DURS200 DURL313 DUR08 DUR13 DUR14 DUR15 MRW_20 MRW_30 MRW_40 MRW_D40A MRW_D40B EDM_02 TST_01 TCS_110 TCS_120 TCS_150 TCS_200
10000 5 1 5 46 1 3 1 1 510 60 120 770 90 0 0 0 0 NA 1 1 1 2 NA 8 2 2 2 2
10001 5 1 1 59 1 4 3 4 420 150 0 0 0 0 0 0 0 NA 2 1 1 2 NA 1 2 2 2 2
10002 4 2 1 47 1 5 1 6 570 0 0 630 30 480 0 0 0 NA NA NA 1 1 NA 7 2 1 1 1
10003 6 2 5 35 1 4 2 4 510 10 45 875 80 20 0 0 0 NA NA NA 1 1 NA 1 2 2 2 2
10004 2 1 6 35 1 NA 1 3 525 90 40 815 0 0 0 0 0 NA NA NA 2 2 NA 1 2 2 2 2
10005 1 1 6 35 1 1 1 6 435 0 0 430 40 530 0 0 0 NA NA NA 1 1 NA 2 2 1 1 2

Viewing Data

To visualize the full dataset we use the View() function. This will open our dataset in a separate window.

View(js_data)

Change Column Names

Let’s now return to the R syntax diagram that we looked at in Block 3:

In that session, we discussed objects and functions, and played with the idea of objects storing information, and functions manipulating the object/data.

Now we’re going to start implementing pipes as a way to connect objects to functions and arguments.

Pipes

Pipes are used to chain steps of instructions or actions together, and often involve writing over an object to give it a new value. We’ll walk through some examples of how this works, and start to see how the full syntax of R comes together.


We mentioned earlier that we wanted to work with column names that were more descriptive of the content of each variable. To change column names we can use the function rename().

The function rename() is part of one of the packages that was installed with tidyverse.

Type the following code to change the column name from “PUMFID” to “id”

js_data <- js_data |>
  rename("id" = "PUMFID")

Step-by-step explanation:

  • This command first starts off with the js_data object, which is our dataset.
  • The assignment operator comes next, and will re-write the information stored in js_data with all the information that is to the right side of the operator.
  • We then use the js_data object and the pipe |> to tell R that we want to take the data that is stored in js_data, and then do something to it (which is what comes after the pipe).
  • The rename function is used to rename columns, and is always followed by brackets. Inside those brackets, we’ll put the new column name that we want in quotation marks "", followed by an equal sign =, followed by the existing column name in quotation marks "".
  • We then run the command and hope it works!

Your Turn!

First, use the functionnames() to display the column names.

names(js_data)

Now, see if you can change the AGEGR10 column name to ageGrp

js_data <- js_data |>
  rename("ageGrp" = "AGEGR10")

Next, try to change the following 3 column names:

  • Change SEX to sex
  • Change MARSTAT to maritalStat
  • Change PRV to province

Hint: It can be tedious to do these changes one by one, but by using commas , you can rename column names with a single code chunk.

js_data <- js_data |>
  rename("sex" = "SEX",
          "maritalStat" = "MARSTAT",
          "province" = "PRV")

Now, to change the rest of the column names copy the following code. (If you feel you’re starting to understand how this works, you can show the code below and cope + paste it into your script, or if you want some more practice, feel free to do it yourself!

js_data <- js_data |>
  rename("popCenter" = "LUC_RST",
          "eduLevel" = "EHG_ALL",
          "feelRushed" = "GTU_110",
          "extraTime" = "GTU_130",
          "durSleep" = "DUR01",
          "durMealPrep" = "DUR05",
          "durEating" = "DUR06",
          "durAlone" = "DURS200",
          "durDriving" = "DURL313",
          "durWork" = "DUR08",
          "durShoolSite" = "DUR13",
          "durSchoolOnline" = "DUR14",
          "durStudy" = "DUR15",
          "mainStudy" = "MRW_20",
          "mainJobHunting" = "MRW_30",
          "mainWork" = "MRW_40",
          "worked12m" = "MRW_D40A",
          "workedWeek" = "MRW_D40B",
          "enrollStat" = "EDM_02",
          "dailyTexts" = "TST_01",
          "timeSlowDown" = "TCS_110",
          "timeWorkaholic" = "TCS_120",
          "timeNotFamFriends" = "TCS_150",
          "timeWantAlone" = "TCS_200")

Save Your Work

Now that we’ve created a dataset that has some significant changes, it can be helpful to save this as a version that we can easily return to. Much like we did with reading .csv data into R, there is a similar command to save, or “write” .csv data back to your computer called write_csv(). The syntax is as follows:

write_csv(data-object-name, file="file-path/datafile-name.csv")

The file name below is for example purposes, and feel free to use a file naming convention that you developed:

write_csv(js_data, file="data/clean-cols.csv")


.RData Files

An additional way to save data files in R is as an .Rdata file. Unlike a simple .csv file, .RData files are designed to store R objects and your entire R workspace, while maintain their data types and structures (covered in the next session!). This allows you to return to your R environment exactly as you left it when you reload the file, and allows others opening your files to have that environment as well, acting as a great way to faciliate reproducibility.

The syntax is similar is the same as write_csv, but uses the function save():

save(js_data, file="data/clean-cols.RData")


When opening an .RData file, instead of using read_csv(), you use the load() command. The syntax is the same, and to reopen the file you just saved would look like this:

`load("data/clean-cols.RData")`
LS0tDQp0aXRsZTogIkZpcnN0IHN0ZXBzIGluIFIiDQpwYWdldGl0bGU6ICJGaXJzdCBzdGVwcyBpbiBSIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZm9sZGluZzogc2hvdyAjIGFsbG93cyB0b2dnbGluZyBvZiBzaG93aW5nIGFuZCBoaWRpbmcgY29kZS4gUmVtb3ZlIGlmIG5vdCB1c2luZyBjb2RlLg0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgIyBhbGxvd3MgdGhlIHVzZXIgdG8gZG93bmxvYWQgdGhlIHNvdXJjZSAuUm1kIGZpbGUuIFJlbW92ZSBpZiBub3QgdXNpbmcgY29kZS4NCiAgICBpbmNsdWRlczoNCiAgICAgIGFmdGVyX2JvZHk6IGZvb3Rlci5odG1sICMgaW5jbHVkZSBhIGN1c3RvbSBmb290ZXIuDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UNCi0tLQ0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5ncyA9IEZBTFNFKQ0KYGBgDQoNCiMjIEZpcnN0IFN0ZXBzIGluIFINCg0KKipJbiBvcmRlciB0byBmb2xsb3cgYWxvbmcgd2l0aCB0aGlzIHNlc3Npb24sIHlvdSdsbCBuZWVkIHRvIGhhdmUgZG93bmxvYWRlZCBzb21lIG9mIHRoZSBmaWxlcyBpbiB0aGUgT1NGIHJlcG8gZm9yIHRoaXMgc2VyaWVzLiAgSWYgeW91IGhhdmVuJ3QgZG9uZSBzbywgZ28gdG8gdGhpcyBwYWdlIGFuZCBzZWxlY3QgdGhlICJEb3dubG9hZCB0aGlzIGZvbGRlciIgYnV0dG9uIG9uIHRoZSB0b3AgcmlnaHQgb2YgdGhlIHNjcmVlbjoqKiBbZG93bmxvYWQgT1NGIGZpbGVzXShodHRwczovL29zZi5pby9yeDVhMy9maWxlcy9vc2ZzdG9yYWdlKQ0KDQpJZiB5b3UgaGF2ZSBhbnkgaXNzdWVzLCBwbGVhc2UgYXNrIHlvdXIgaW5zdHJ1Y3Rvciwgb3IgcmVmZXIgdG8gKioiQmxvY2sgMTogSW50cm9kdWN0aW9uIHRvIE9TRiIqKi4NCg0KDQojIyBJbnRyb2R1Y3Rpb24NCg0KOjo6aW50cm8NCk5vdyB0aGF0IHdlJ3ZlIGZhbWlsaWFyaXplZCBvdXJzZWx2ZXMgYSBiaXQgd2l0aCBSIGFuZCBSU3R1ZGlvLCB3ZSBjYW4gc3RhcnQgbW92aW5nIGZvcndhcmQgdG8gd29ya2luZyB3aXRoIGRhdGEgaW4gUiwgd2hpY2ggaXMgd2hlcmUgdGhlIHJlYWwgZnVuIGJlZ2lucyENCjo6Og0KDQojIyBSIFByb2plY3RzIA0KDQojIyMgU2V0dGluZyB3b3JraW5nIGRpcmVjdG9yeQ0KDQpXaGVuIHdlIHRhbGtlZCBhYm91dCByZWxhdGl2ZSBmaWxlIHBhdGhzIGluIHRoZSBwcmV2aW91cyBzZXNzaW9uLCBpdCB3YXMgcmV2b2x2aW5nIGFyb3VuZCB0aGlzIGlkZWEgb2YgKndoZXJlIHlvdSBhcmUgaW4gdGhlIGZpbGUgc3lzdGVtKi4gIEluIGEgY29kaW5nIGVudmlyb25tZW50LCB0aGlzIHRyYW5zbGF0ZXMgdG8gdGhlIGlkZWEgb2YgKipzZXR0aW5nIGEgd29ya2luZyBkaXJlY3RvcnkqKiwgd2hpY2ggaXMgYSB3YXkgb2YgdGVsbGluZyBSIChvciBvdGhlciBjb2RpbmcgbGFuZ3VhZ2VzKSB3aGVyZSB5b3Ugd2FudCB0byBiZSBpbiB5b3VyIGNvbXB1dGVyJ3MgZmlsZSBzeXN0ZW0gd2hlbiB5b3UncmUgZG9pbmcgeW91ciB3b3JrLiAgDQoNCkEgY29tbW9uIHdheSB0byBzZXQgYSB3b3JraW5nIGRpcmVjdG9yeSBpcyB0byB1c2UgdGhlIGBzZXR3ZCgpYCBmdW5jdGlvbi4gVGhpcyBmdW5jdGlvbiBtYW51YWxseSBzZXRzIHRoZSB3b3JraW5nIGRpcmVjdG9yeSBkdXJpbmcgYW4gUiBzZXNzaW9uLiBJdCB0ZWxscyBSIHdoZXJlIHRvIGxvb2sgZm9yIGZpbGVzIGFuZCB3aGVyZSB0byBzYXZlIG91dHB1dHMganVzdCBmb3IgdGhhdCBzZXNzaW9uLg0KDQpUaGlzIGNhbiBiZSBkb25lIGluIDIgd2F5czoNCg0KKiBNYW51YWxseSBpbiBSLCBieSB3cml0aW5nIGBzZXR3ZCgicGF0aC10by1kaXJlY3Rvci9zZWNvbmRhcnktcGFydC9ldGMuLi4iKWANCiogU2V0dGluZyBpdCBieSBzZWxlY3RpbmcgdGhlIGBTZXNzaW9uYCB0YWIgaW4gdGhlIHRvb2xiYXIsIGFuZCBzZWxlY3RpbmcgYFNldCBXb3JraW5nIERpcmVjdG9yeWA6DQoNCiFbXShpbWFnZXMvYmxvY2s0LTFfc2V0LXdkLmdpZikNCg0KDQpCdXQgaGVyZeKAmXMgdGhlIHByb2JsZW0uLi4NCg0KVXNpbmcgYHNldHdkKClgIGNhbiBicmVhayB5b3VyIGNvZGUgd2hlbjoNCg0KIC0gU29tZW9uZSBlbHNlIHRyaWVzIHRvIHJ1biBpdCBvbiB0aGVpciBtYWNoaW5lLg0KIC0gWW91IG1vdmUgeW91ciBwcm9qZWN0IGZvbGRlci4NCiAtIFlvdSdyZSBydW5uaW5nIHlvdXIgY29kZSBvbiBhIHNlcnZlciBvciBpbiBjbG91ZCBlbnZpcm9ubWVudHMgbGlrZSBSU3R1ZGlvIENsb3VkLg0KDQpTaW5jZSBmaWxlIHBhdGhzIGFyZSBoYXJkY29kZWQgYW5kIGRlcGVuZCBvbiB5b3VyIG1hY2hpbmUsICoqaXQncyBub3QgcmVwcm9kdWNpYmxlKiouDQoNCiMjIyBDcmVhdGUgYW4gUiBQcm9qZWN0DQoNCkFuIFIgUHJvamVjdCBpcyBhIGZlYXR1cmUgaW4gUlN0dWRpbyAoYW5kIHN1cHBvcnRlZCBpbiBiYXNlIFIgdG9vKSB0aGF0IHByb3ZpZGVzIGEgc2VsZi1jb250YWluZWQgd29ya2luZyBlbnZpcm9ubWVudC4gV2hlbiB5b3UgY3JlYXRlIGFuIFIgUHJvamVjdCBpdCBjcmVhdGVzIGEgLlJwcm9qIGZpbGUgaW4gYSBmb2xkZXIgYW5kIHRoYXQgZm9sZGVyIGJlY29tZXMgdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHlvdXIgcHJvamVjdC4gRXZlcnkgdGltZSB5b3Ugb3BlbiB0aGUgcHJvamVjdCAodmlhIHRoZSAuUnByb2ogZmlsZSksIFIgYXV0b21hdGljYWxseSBzZXRzIHRoZSB3b3JraW5nIGRpcmVjdG9yeSB0byB0aGF0IGZvbGRlci4gWW91IGNhbiByZWZlcmVuY2UgZmlsZXMgcmVsYXRpdmUgdG8gdGhlIHByb2plY3Qgcm9vdCDigJQgbm8gbmVlZCB0byBoYXJkY29kZSBmaWxlIHBhdGhzLg0KDQpUaGlzIGlzIHN1cGVyIHVzZWZ1bCB3aGVuIHlvdSdyZSB3b3JraW5nIG9uIG11bHRpcGxlIGFuYWx5c2VzLCBzaGFyaW5nIGNvZGUgd2l0aCBjb2xsYWJvcmF0b3JzLCBvciB2ZXJzaW9uLWNvbnRyb2xsaW5nIHdpdGggR2l0LiAqKkl0IGlzIGEgZ29vZCBwcmFjdGljZSBmb3IgcmVwcm9kdWNpYmxlIHJlc2VhcmNoKioNCg0KVG8gY3JlYXRlIGFuIFIgUHJvamVjdCwgc2VsZWN0IEZpbGUgPiBOZXcgUHJvamVjdA0KDQohW10oaW1hZ2VzL2RheTJfQ3JlYXRlUHJvamVjdC5naWYpDQoNCg0KIyMgWW91ciBUdXJuIQ0KDQo6OjpxdWVzdGlvbg0KQ3JlYXRlIHlvdXIgZmlyc3QgUlByb2plY3QuIExldCdzIGZpZ3VyZSBvdXQgd2hhdCB3ZSBzaG91bGQgY2FsbCBpdCENCjo6Og0KDQoNCiMjIFBhY2thZ2VzIGFuZCBMaWJyYXJpZXMNCg0KV2hlbiB5b3UgZmlyc3QgZG93bmxvYWQgUiwgaXQgY29tZXMgZXF1aXBwZWQgd2l0aCBhIG51bWJlciBvZiBwcmUtaW5zdGFsbGVkIGZ1bmN0aW9ucywgb3IgY2FwYWJpbGl0aWVzLCB0aGF0IHlvdSBjYW4gc3RhcnQgdXNpbmcgaW1tZWRpYXRlbHkuICBUaGlzIGlzIG9mdGVuIGNhbGxlZCAiQmFzZSBSOi4gIEhvd2V2ZXIsIGZvciBjZXJ0YWluIHRhc2tzIGFuZCB3b3JrZmxvd3MsIGl0IGNhbiBiZSBiZW5lZmljaWFsIHRvIHVzZSBtb3JlIHNwZWNpYWxpemVkIHRvb2xzLCBvciBmdW5jdGlvbnMsIHRvIGFjY29tcGxpc2ggd29yayBhbmQgZmFjaWxpdGF0ZSB3b3JrZmxvd3MgZm9yIGVmZmljaWVudGx5LiAgVGhpcyBpcyB3aGVyZSBwYWNrYWdlcyBhbmQgbGlicmFyaWVzIGNvbWUgaW50byBwbGF5Lg0KDQo6Ojpub3RlDQoNCiogKipQYWNrYWdlcyoqOiBQYWNrYWdlcyBhcmUgYW4gZXh0ZW5zaW9uIG9mIHRoZSBwcmUtYnVpbHQgZnVuY3Rpb25zIGluIFIsIGFuZCBjYW4gYmUgaW5zdGFsbGVkIHRvIGJyaW5nIGluIHNwZWNpZmljIGZ1bmN0aW9ucyB0byBhY2NvbXBsaXNoIHRhc2tzLCBicmluZyBpbiBzYW1wbGUgZGF0YXNldHMgdG8gcGxheSB3aXRoLCBhbW9uZyBvdGhlciB0aGluZ3MuICBUaGVyZSBhcmUgKip0b25zKiogb2YgUiBwYWNrYWdlcyBvdXQgdGhlcmUsIGJ1dCBoZXJlIGlzIGEgbGlzdCBvZiBzb21lIG9mIHRoZSBtb3N0IGNvbW1vbi91c2VmdWwgb25lczogW1F1aWNrIGxpc3Qgb2YgdXNlZnVsIFIgcGFja2FnZXNdKGh0dHBzOi8vc3VwcG9ydC5wb3NpdC5jby9oYy9lbi11cy9hcnRpY2xlcy8yMDEwNTc5ODctUXVpY2stbGlzdC1vZi11c2VmdWwtUi1wYWNrYWdlcykNCg0KKiAqKkxpYnJhcmllcyoqOiBPbmNlIHlvdSBoYXZlIGluc3RhbGxlZCBhIHBhY2thZ2UsIHRoZXkgYXJlIHN0b3JlZCBhcyBsaWJyYXJpZXMgaW4gUi4gIFlvdSBvbmx5IGhhdmUgdG8gaW5zdGFsbCB0aGVtIG9uY2UsIGFuZCBhbnl0aW1lIHlvdSB3YW50IHRvIHVzZSB0aGUgcGFja2FnZSB5b3UgY2FuIHVzZSB0aGUgYGxpYnJhcnkoKWAgZnVuY3Rpb24sIHdoaWNoIGlzIGRlc2NyaWJlZCBiZWxvdy4NCg0KOjo6DQoNCg0KIyMjIFRpZHl2ZXJzZQ0KDQpBcyBtZW50aW9uZWQgaW4gdGhlIHNlc3Npb24gKioiUmVwcm9kdWNpYmxlIFJlc2VhcmNoOiBNb3ZpbmcgRnJvbSBFeGNlbCB0byBTY3JpcHRpbmciKiosIHdlIHdpbGwgYmUgdXNpbmcgYW4gUiBwYWNrYWdlIGNhbGxlZCB0aGUgKioiVGlkeXZlcnNlIioqLiAgVGhlIFRpZHl2ZXJzZSBpcyBhIHZlcnkgY29tbW9ubHkgdXNlZCBwYWNrYWdlIGZvciByZXNlYXJjaCBhbmQgZGF0YSBzY2llbmNlIGFjdGl2aXRpZXMsIGFuZCBpbnN0ZWFkIG9mIGJlaW5nIGEgc2luZ2xlIHBhY2thZ2UsIGl0IGlzIGEgY29sbGVjdGlvbiBvZiBwYWNrYWdlcyB0aGF0IGFyZSBkZXNpZ25lZCB0byB3b3JrIHRvZ2V0aGVyIGFuZCB3aGljaCBmb2N1cyBvbiB0aGUgY29ubmVjdGlvbnMgYmV0d2VlbiBhY3Rpdml0aWVzIGluIHRoZSBkYXRhIHNjaWVuY2Ugd29ya2Zsb3cuICBFYWNoIHBhY2thZ2UgZm9sbG93cyB0aGUgc2FtZSBzeW50YXgsIHdoaWNoIG1ha2VzIGxlYXJuaW5nIHRoZW0gZWFzaWVyLCBhbmQgdGhlIHdlYnNpdGUgZnVuY3Rpb25zIGFzIGEgcmVhbGx5IGdvb2QgcmVmZXJlbmNlIHBvaW50IGlmIHlvdSdyZSBzdHJ1Z2dsaW5nIHdpdGggaG93IHRvIGFwcHJvYWNoIGEgc3BlY2lmaWMgdGFzay4NCg0KIVtdKGltYWdlcy9ibG9jazRfZGF0YS1zY2llbmNlLXdvcmtmbG93LmpwZykNCg0KDQpMZXQncyB0YWtlIGEgY2xvc2VyIGxvb2shICBbVGlkeXZlcnNlXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnL3BhY2thZ2VzLykNCg0KPGJyPg0KDQojIyBMZXQncyBnZXQgc3RhcnRlZCENCg0KRmlyc3QsIGxldCdzIGNyZWF0ZSBhIG5ldyBSIHNjcmlwdC4NCg0KVG8gY3JlYXRlIGFuIFIgc2NyaXB0IGZpbGUsIHNlbGVjdCBGaWxlID4gTmV3IEZpbGUgPiBSIFNjcmlwdA0KDQohW10oaW1hZ2VzL2Jsb2NrM19jcmVhdGUtci1zY3JpcHQuZ2lmKQ0KDQoNCiMjIyBJbnN0YWxsIFBhY2thZ2UNClRvIGluc3RhbGwgYSBwYWNrYWdlIHdlIHVzZSB0aGUgZnVuY3Rpb24gYGluc3RhbGwucGFja2FnZXMoKWAuIA0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KYGBgDQoNCiMjIyBMb2FkIExpYnJhcmllcw0KUGFja2FnZXMgYXJlIHN0b3JlZCBpbiBsaWJyYXJpZXMuIE9uY2UgYSBwYWNrYWdlIGlzIGluc3RhbGxlZCwgd2UgbmVlZCB0byBjYWxsIHRoZSBsaWJyYXJ5IHdpdGggdGhlIGZ1bmN0aW9uIGBsaWJyYXJ5KClgLg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCjo6OmZsYWcNCk5vdGUgdGhhdCB0aGUgcGFja2FnZSBuYW1lIG5lZWRzIHRvIGJlIGluIHF1b3RhdGlvbnMgd2hlbiBpbnN0YWxsaW5nIHRoZSBwYWNrYWdlLCBidXQgbm90IHdoZW4gbG9hZGluZyB0aGUgbGlicmFyeS4NCg0KQmVjYXVzZSBwYWNrYWdlcyBvbmx5IG5lZWQgdG8gYmUgaW5zdGFsbGVkIG9uY2UsIHdlIGNhbiBkbyB0aGlzIGluIHRoZSBSIGNvbnNvbGUgYXMgb3Bwb3NlZCB0byBpbiB0aGUgc2NyaXB0Lg0KDQpCZWNhdXNlIGxpYnJhcmllcyBuZWVkIHRvIGJlIGxvYWRlZCBpbiBlYWNoIHdvcmtpbmcgc2Vzc2lvbiwgd2UgY2FuIGRvIHRoaXMgaW4gdGhlIFIgc2NyaXB0IHNvIHRoYXQgb3RoZXJzIGNhbiBzZWUgd2hhdCBsaWJyYXJpZXMgd2UgYXJlIHVzaW5nIGFuZCBuZWVkIHRvIGJlIGxvYWRlZC4NCjo6Og0KDQoNClJlZmVycmluZyBhZ2FpbiB0byB0aGUgVGlkeXZlcnNlIERhdGEgU2NpZW5jZSBXb3JrZmxvdywgaW4gdGhpcyBzZXNzaW9uIHdlJ2xsIGJlIGZvY3VzaW5nIG9uIHRoZSBmaXJzdCB0d28gc3RlcHM6DQoNCiFbXShpbWFnZXMvZGF5Ml93b3JrZmxvdy5wbmcpDQo8YSBocmVmPSJodHRwczovL3RlbGFwcHMubG9uZG9uLmVkdS9hbmFseXRpY3Nfd2l0aF9SL3RpZHl2ZXJzZS5odG1sIj5Tb3VyY2U8L2E+DQoNCiMjIFJlYWRpbmcgRGF0YQ0KDQpJbiBvcmRlciB0byBzdGFydCB3b3JraW5nIHdpdGggYSBkYXRhc2V0IGluIFIsIHdlIGZpcnN0IG5lZWQgdG8gaW1wb3J0LCBvciAicmVhZCBpbiIsIHRoZSBkYXRhLiAgQXMgbWVudGlvbmVkIGluIHRoZSBzZXNzaW9uICoqIlJlcHJvZHVjaWJsZSBSZXNlYXJjaDogTW92aW5nIEZyb20gRXhjZWwgdG8gU2NyaXB0aW5nIioqLCB3ZSB3aWxsIGJlIHdvcmtpbmcgd2l0aCBgLmNzdmAgZmlsZXMsIGJ1dCBSIGlzIGNhcGFibGUgb2YgcmVhZGluZyBpbiBvdGhlciBmaWxlIHR5cGVzIGFzIHdlbGwuDQoNCg0KIyMjIFJlYWQgYSBjc3YgZmlsZQ0KVG8gaW1wb3J0IGEgY3N2IGZpbGUgd2UgY2FuIHVzZSB0aGUgYHJlYWRfY3N2KClgIGZ1bmN0aW9uIGFuZCBhc3NpZ24gaXQgdG8gYSBuZXcgb2JqZWN0IHdlIHdpbGwgY2FsbCAqanNfZGF0YSouIFdlIGNyZWF0ZSBhIG5ldyBvYmplY3QgdG8gYmUgYWJsZSB0byBjYWxsIGl0IGluIGRpZmZlcmVudCBmdW5jdGlvbnMgbGF0ZXIgb24uDQpgYGB7cn0NCmpzX2RhdGEgPC0gcmVhZF9jc3YoImRhdGEvYmxvY2stNF9maXJzdC1zdGVwcy5jc3YiKQ0KYGBgDQoNCiMjIyBSZWFkIE90aGVyIEZvcm1hdHMNCkluIHRoZSBleGFtcGxlIHdlIGFyZSB3b3JraW5nIHdpdGggdGhlIGRhdGEgaXMgc3RvcmVkIGluIGEgY3N2IGZpbGUuIFRoZSBwYWNrYWdlICoqcmVhZHIqKiBmcm9tIFRpZHl2ZXJzZSBjYW4gYWxzbyByZWFkIG90aGVyIGZvcm1hdHMgbGlrZSBgcmVhZF90c3YoKWAodGFiLXNlcGFyYXRlZCB2YWx1ZXMpLCBgcmVhZF9kZWxpbSgpYChkZWxpbWl0ZWQgZmlsZXMgQ1NWIGFuZCBUU1YpLCBgcmVhZF90YWJsZSgpYCh3aGl0ZXNwYWNlLXNlcGFyYXRlZCBmaWxlcyksIGByZWFkX2xvZygpYCh3ZWIgbG9nIGZpbGVzKS4NCg0KVGhlcmUgYXJlIG90aGVyIGZ1bmN0aW9ucyBhbmQgcGFja2FnZXMgdGhhdCBhbGxvdyB1cyB0byBpbXBvcnQgZGlmZmVyZW50IGZpbGUgdHlwZXMuIA0KDQoqKkZpbGUgVHlwZSoqIHwqKkZ1bmN0aW9uKiogfCAqKlBhY2thZ2UqKg0KfDotLS0tLS18Oi0tLS0tLXw6LS0tLS0tLXwNCnwuY3N2IHwgYHJlYWRfY3N2KClgfCByZWFkciB8DQp8IC54bHN4IHwgYHJlYWQueGxzeCgpYHwgeGxzeCB8DQp8IC5zYXYgfCBgcmVhZF9zYXYoKWB8IGhhdmVuIHwNCnwgLnNhczdiZGF0ICwgLnNhczdiY2F0IHwgYHJlYWRfc2FzKClgfCBoYXZlbiB8DQp8IC5kdGEgfCBgcmVhZF9kdGEoKWB8IGhhdmVuIHwNCg0KIyMgTGlzdGluZyBDb2x1bW4gTmFtZXMNClRvIGFzayBmb3IgYSBsaXN0IG9mIGFsbCB0aGUgY29sdW1uIG5hbWVzIGluIG91ciBkYXRhc2V0IHdlIGNhbiB1c2UgdGhlIGBuYW1lcygpYCBmdW5jdGlvbi4NCmBgYHtyfQ0KbmFtZXMoanNfZGF0YSkNCmBgYA0KDQpOb3RpY2UgdGhhdCB0aGUgY29sdW1uIG5hbWVzIGZyb20gdGhlIG9yaWdpbmFsIGRhdGFzZXQgZG9uJ3QgcHJvdmlkZSBhIGNsZWFyIGRlc2NyaXB0aW9uIG9mIHdoYXQgdGhlIHZhcmlhYmxlIGlzLiBXZSB3aWxsIGNoYW5nZSB0aGUgY29sdW1uIG5hbWVzIGxhdGVyIHRvIGZhY2lsaXRhdGUgd29ya2luZyB3aXRoIG91ciBkYXRhIGluIHRoZSBmdXR1cmUuDQoNCiMjIEhlYWQgRnVuY3Rpb24NClRoZSBoZWFkIGZ1bmN0aW9uIHdpbGwgZGlzcGxheSB0aGUgdG9wIHJvd3Mgb2YgdGhlIGRhdGFzZXQuIEl0IHdpbGwgaW5jbHVkZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZGVmYXVsdCBkYXRhIHR5cGUgYXNzaWduZWQgdG8gZWFjaCBjb2x1bW4uIFdlIHdpbGwgY292ZXIgZGF0YSB0eXBlcyBtb3JlIGluIHRoZSBuZXh0IHNlc3Npb24uDQoNCmBgYHtyLCBkYXRhLWlzb2xhdGlvbiwgcmVzdWx0cyA9IEZBTFNFfQ0KaGVhZChqc19kYXRhKQ0KYGBgDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoa2FibGVFeHRyYSkNCmhlYWQoanNfZGF0YSl8Pg0KICBrYmwoKSB8Pg0KICAja2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIikNCmthYmxlX3BhcGVyKCkgJT4lDQogIHNjcm9sbF9ib3god2lkdGggPSAiNTAwcHgiLCBoZWlnaHQgPSAiMjAwcHgiKQ0KDQpgYGANCg0KIyMgVmlld2luZyBEYXRhDQpUbyB2aXN1YWxpemUgdGhlIGZ1bGwgZGF0YXNldCB3ZSB1c2UgdGhlIGBWaWV3KClgIGZ1bmN0aW9uLiBUaGlzIHdpbGwgb3BlbiBvdXIgZGF0YXNldCBpbiBhIHNlcGFyYXRlIHdpbmRvdy4NCmBgYHtyLCBldmFsPUZBTFNFfQ0KVmlldyhqc19kYXRhKQ0KYGBgDQoNCg0KIyMgQ2hhbmdlIENvbHVtbiBOYW1lcw0KDQpMZXQncyBub3cgcmV0dXJuIHRvIHRoZSBSIHN5bnRheCBkaWFncmFtIHRoYXQgd2UgbG9va2VkIGF0IGluIEJsb2NrIDM6DQoNCiFbXShpbWFnZXMvZGF5Ml9SU3ludGF4LnBuZykNCg0KSW4gdGhhdCBzZXNzaW9uLCB3ZSBkaXNjdXNzZWQgKipvYmplY3RzKiogYW5kICoqZnVuY3Rpb25zKiosIGFuZCBwbGF5ZWQgd2l0aCB0aGUgaWRlYSBvZiBvYmplY3RzIHN0b3JpbmcgaW5mb3JtYXRpb24sIGFuZCBmdW5jdGlvbnMgbWFuaXB1bGF0aW5nIHRoZSBvYmplY3QvZGF0YS4NCg0KTm93IHdlJ3JlIGdvaW5nIHRvIHN0YXJ0IGltcGxlbWVudGluZyAqKnBpcGVzKiogYXMgYSB3YXkgdG8gY29ubmVjdCBvYmplY3RzIHRvICoqZnVuY3Rpb25zKiogYW5kICoqYXJndW1lbnRzKiouDQoNCiMjIyMgUGlwZXMNCg0KUGlwZXMgYXJlIHVzZWQgdG8gY2hhaW4gc3RlcHMgb2YgaW5zdHJ1Y3Rpb25zIG9yIGFjdGlvbnMgdG9nZXRoZXIsIGFuZCBvZnRlbiBpbnZvbHZlIHdyaXRpbmcgb3ZlciBhbiBvYmplY3QgdG8gZ2l2ZSBpdCBhIG5ldyB2YWx1ZS4gV2UnbGwgd2FsayB0aHJvdWdoIHNvbWUgZXhhbXBsZXMgb2YgaG93IHRoaXMgd29ya3MsIGFuZCBzdGFydCB0byBzZWUgaG93IHRoZSBmdWxsIHN5bnRheCBvZiBSIGNvbWVzIHRvZ2V0aGVyLg0KDQo8YnI+DQoNCldlIG1lbnRpb25lZCBlYXJsaWVyIHRoYXQgd2Ugd2FudGVkIHRvIHdvcmsgd2l0aCBjb2x1bW4gbmFtZXMgdGhhdCB3ZXJlIG1vcmUgZGVzY3JpcHRpdmUgb2YgdGhlIGNvbnRlbnQgb2YgZWFjaCB2YXJpYWJsZS4gVG8gY2hhbmdlIGNvbHVtbiBuYW1lcyB3ZSBjYW4gdXNlIHRoZSBmdW5jdGlvbiBgcmVuYW1lKClgLg0KDQpUaGUgZnVuY3Rpb24gYHJlbmFtZSgpYCBpcyBwYXJ0IG9mIG9uZSBvZiB0aGUgcGFja2FnZXMgdGhhdCB3YXMgaW5zdGFsbGVkIHdpdGggdGlkeXZlcnNlLg0KDQo6Ojp3YWxrdGhyb3VnaA0KVHlwZSB0aGUgZm9sbG93aW5nIGNvZGUgdG8gY2hhbmdlIHRoZSBjb2x1bW4gbmFtZSBmcm9tICJQVU1GSUQiIHRvICJpZCINCmBgYHtyfQ0KanNfZGF0YSA8LSBqc19kYXRhIHw+DQogIHJlbmFtZSgiaWQiID0gIlBVTUZJRCIpDQpgYGANCg0KKipTdGVwLWJ5LXN0ZXAgZXhwbGFuYXRpb246KioNCg0KKiBUaGlzIGNvbW1hbmQgZmlyc3Qgc3RhcnRzIG9mZiB3aXRoIHRoZSBganNfZGF0YWAgb2JqZWN0LCB3aGljaCBpcyBvdXIgZGF0YXNldC4NCiogVGhlIGFzc2lnbm1lbnQgb3BlcmF0b3IgY29tZXMgbmV4dCwgYW5kIHdpbGwgcmUtd3JpdGUgdGhlIGluZm9ybWF0aW9uIHN0b3JlZCBpbiBganNfZGF0YWAgd2l0aCBhbGwgdGhlIGluZm9ybWF0aW9uIHRoYXQgaXMgdG8gdGhlIHJpZ2h0IHNpZGUgb2YgdGhlIG9wZXJhdG9yLg0KKiBXZSB0aGVuIHVzZSB0aGUgYGpzX2RhdGFgIG9iamVjdCBhbmQgdGhlIHBpcGUgYHw+YCB0byB0ZWxsIFIgdGhhdCB3ZSB3YW50IHRvIHRha2UgdGhlIGRhdGEgdGhhdCBpcyBzdG9yZWQgaW4gYGpzX2RhdGFgLCBhbmQgdGhlbiBkbyBzb21ldGhpbmcgdG8gaXQgKHdoaWNoIGlzIHdoYXQgY29tZXMgYWZ0ZXIgdGhlIHBpcGUpLg0KKiBUaGUgYHJlbmFtZWAgZnVuY3Rpb24gaXMgdXNlZCB0byByZW5hbWUgY29sdW1ucywgYW5kIGlzIGFsd2F5cyBmb2xsb3dlZCBieSBicmFja2V0cy4gIEluc2lkZSB0aG9zZSBicmFja2V0cywgd2UnbGwgcHV0IHRoZSBuZXcgY29sdW1uIG5hbWUgdGhhdCB3ZSB3YW50IGluIHF1b3RhdGlvbiBtYXJrcyBgIiJgLCBmb2xsb3dlZCBieSBhbiBlcXVhbCBzaWduIGA9YCwgZm9sbG93ZWQgYnkgdGhlIGV4aXN0aW5nIGNvbHVtbiBuYW1lIGluIHF1b3RhdGlvbiBtYXJrcyBgIiJgLg0KKiBXZSB0aGVuIHJ1biB0aGUgY29tbWFuZCBhbmQgaG9wZSBpdCB3b3JrcyENCjo6Og0KDQojIyBZb3VyIFR1cm4hDQoNCjo6OnF1ZXN0aW9uDQpGaXJzdCwgdXNlIHRoZSBmdW5jdGlvbmBuYW1lcygpYCB0byBkaXNwbGF5IHRoZSBjb2x1bW4gbmFtZXMuDQpgYGB7ciwgZXZhbD1GQUxTRX0NCm5hbWVzKGpzX2RhdGEpDQpgYGANCjo6Og0KDQo6OjpxdWVzdGlvbg0KTm93LCBzZWUgaWYgeW91IGNhbiBjaGFuZ2UgdGhlIGBBR0VHUjEwYCBjb2x1bW4gbmFtZSB0byBgYWdlR3JwYA0KYGBge3IsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnfQ0KanNfZGF0YSA8LSBqc19kYXRhIHw+DQogIHJlbmFtZSgiYWdlR3JwIiA9ICJBR0VHUjEwIikNCmBgYA0KDQo6OjoNCg0KOjo6cXVlc3Rpb24NCk5leHQsIHRyeSB0byBjaGFuZ2UgdGhlIGZvbGxvd2luZyAzIGNvbHVtbiBuYW1lczoNCg0KKiBDaGFuZ2UgYFNFWGAgdG8gYHNleGANCiogQ2hhbmdlIGBNQVJTVEFUYCB0byBgbWFyaXRhbFN0YXRgDQoqIENoYW5nZSBgUFJWYCB0byBgcHJvdmluY2VgDQoNCioqSGludDoqKiBJdCBjYW4gYmUgdGVkaW91cyB0byBkbyB0aGVzZSBjaGFuZ2VzIG9uZSBieSBvbmUsIGJ1dCBieSB1c2luZyBjb21tYXMgYCxgIHlvdSBjYW4gcmVuYW1lIGNvbHVtbiBuYW1lcyB3aXRoIGEgc2luZ2xlIGNvZGUgY2h1bmsuICANCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30NCmpzX2RhdGEgPC0ganNfZGF0YSB8Pg0KICByZW5hbWUoInNleCIgPSAiU0VYIiwNCiAgICAgICAgICAibWFyaXRhbFN0YXQiID0gIk1BUlNUQVQiLA0KICAgICAgICAgICJwcm92aW5jZSIgPSAiUFJWIikNCmBgYA0KOjo6DQoNCjo6OnF1ZXN0aW9uDQpOb3csIHRvIGNoYW5nZSB0aGUgcmVzdCBvZiB0aGUgY29sdW1uIG5hbWVzIGNvcHkgdGhlIGZvbGxvd2luZyBjb2RlLiAoSWYgeW91IGZlZWwgeW91J3JlIHN0YXJ0aW5nIHRvIHVuZGVyc3RhbmQgaG93IHRoaXMgd29ya3MsIHlvdSBjYW4gc2hvdyB0aGUgY29kZSBiZWxvdyBhbmQgYGNvcGUgKyBwYXN0ZWAgaXQgaW50byB5b3VyIHNjcmlwdCwgb3IgaWYgeW91IHdhbnQgc29tZSBtb3JlIHByYWN0aWNlLCBmZWVsIGZyZWUgdG8gZG8gaXQgeW91cnNlbGYhDQoNCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30NCmpzX2RhdGEgPC0ganNfZGF0YSB8Pg0KICByZW5hbWUoInBvcENlbnRlciIgPSAiTFVDX1JTVCIsDQogICAgICAgICAgImVkdUxldmVsIiA9ICJFSEdfQUxMIiwNCiAgICAgICAgICAiZmVlbFJ1c2hlZCIgPSAiR1RVXzExMCIsDQogICAgICAgICAgImV4dHJhVGltZSIgPSAiR1RVXzEzMCIsDQogICAgICAgICAgImR1clNsZWVwIiA9ICJEVVIwMSIsDQogICAgICAgICAgImR1ck1lYWxQcmVwIiA9ICJEVVIwNSIsDQogICAgICAgICAgImR1ckVhdGluZyIgPSAiRFVSMDYiLA0KICAgICAgICAgICJkdXJBbG9uZSIgPSAiRFVSUzIwMCIsDQogICAgICAgICAgImR1ckRyaXZpbmciID0gIkRVUkwzMTMiLA0KICAgICAgICAgICJkdXJXb3JrIiA9ICJEVVIwOCIsDQogICAgICAgICAgImR1clNob29sU2l0ZSIgPSAiRFVSMTMiLA0KICAgICAgICAgICJkdXJTY2hvb2xPbmxpbmUiID0gIkRVUjE0IiwNCiAgICAgICAgICAiZHVyU3R1ZHkiID0gIkRVUjE1IiwNCiAgICAgICAgICAibWFpblN0dWR5IiA9ICJNUldfMjAiLA0KICAgICAgICAgICJtYWluSm9iSHVudGluZyIgPSAiTVJXXzMwIiwNCiAgICAgICAgICAibWFpbldvcmsiID0gIk1SV180MCIsDQogICAgICAgICAgIndvcmtlZDEybSIgPSAiTVJXX0Q0MEEiLA0KICAgICAgICAgICJ3b3JrZWRXZWVrIiA9ICJNUldfRDQwQiIsDQogICAgICAgICAgImVucm9sbFN0YXQiID0gIkVETV8wMiIsDQogICAgICAgICAgImRhaWx5VGV4dHMiID0gIlRTVF8wMSIsDQogICAgICAgICAgInRpbWVTbG93RG93biIgPSAiVENTXzExMCIsDQogICAgICAgICAgInRpbWVXb3JrYWhvbGljIiA9ICJUQ1NfMTIwIiwNCiAgICAgICAgICAidGltZU5vdEZhbUZyaWVuZHMiID0gIlRDU18xNTAiLA0KICAgICAgICAgICJ0aW1lV2FudEFsb25lIiA9ICJUQ1NfMjAwIikNCmBgYA0KDQo6OjoNCg0KIyMgU2F2ZSBZb3VyIFdvcmsNCg0KDQpOb3cgdGhhdCB3ZSd2ZSBjcmVhdGVkIGEgZGF0YXNldCB0aGF0IGhhcyBzb21lIHNpZ25pZmljYW50IGNoYW5nZXMsIGl0IGNhbiBiZSBoZWxwZnVsIHRvIHNhdmUgdGhpcyBhcyBhIHZlcnNpb24gdGhhdCB3ZSBjYW4gZWFzaWx5IHJldHVybiB0by4gIE11Y2ggbGlrZSB3ZSBkaWQgd2l0aCByZWFkaW5nIGAuY3N2YCBkYXRhIGludG8gUiwgdGhlcmUgaXMgYSBzaW1pbGFyIGNvbW1hbmQgdG8gc2F2ZSwgb3IgIndyaXRlIiBgLmNzdmAgZGF0YSBiYWNrIHRvIHlvdXIgY29tcHV0ZXIgY2FsbGVkIGB3cml0ZV9jc3YoKWAuICBUaGUgc3ludGF4IGlzIGFzIGZvbGxvd3M6DQoNCmB3cml0ZV9jc3YoZGF0YS1vYmplY3QtbmFtZSwgZmlsZT0iZmlsZS1wYXRoL2RhdGFmaWxlLW5hbWUuY3N2IilgDQoNClRoZSBmaWxlIG5hbWUgYmVsb3cgaXMgZm9yIGV4YW1wbGUgcHVycG9zZXMsIGFuZCBmZWVsIGZyZWUgdG8gdXNlIGEgZmlsZSBuYW1pbmcgY29udmVudGlvbiB0aGF0IHlvdSBkZXZlbG9wZWQ6DQoNCmBgYHtyfQ0Kd3JpdGVfY3N2KGpzX2RhdGEsIGZpbGU9ImRhdGEvY2xlYW4tY29scy5jc3YiKQ0KYGBgDQoNCjxicj4NCg0KIyMjIC5SRGF0YSBGaWxlcw0KDQpBbiBhZGRpdGlvbmFsIHdheSB0byBzYXZlIGRhdGEgZmlsZXMgaW4gUiBpcyBhcyBhbiBgLlJkYXRhYCBmaWxlLiAgVW5saWtlIGEgc2ltcGxlIGAuY3N2YCBmaWxlLCBgLlJEYXRhYCBmaWxlcyBhcmUgZGVzaWduZWQgdG8gc3RvcmUgUiBvYmplY3RzIGFuZCB5b3VyIGVudGlyZSBSIHdvcmtzcGFjZSwgd2hpbGUgbWFpbnRhaW4gdGhlaXIgZGF0YSB0eXBlcyBhbmQgc3RydWN0dXJlcyAoY292ZXJlZCBpbiB0aGUgbmV4dCBzZXNzaW9uISkuICBUaGlzIGFsbG93cyB5b3UgdG8gcmV0dXJuIHRvIHlvdXIgUiBlbnZpcm9ubWVudCBleGFjdGx5IGFzIHlvdSBsZWZ0IGl0IHdoZW4geW91IHJlbG9hZCB0aGUgZmlsZSwgYW5kIGFsbG93cyBvdGhlcnMgb3BlbmluZyB5b3VyIGZpbGVzIHRvIGhhdmUgdGhhdCBlbnZpcm9ubWVudCBhcyB3ZWxsLCBhY3RpbmcgYXMgYSBncmVhdCB3YXkgdG8gZmFjaWxpYXRlIHJlcHJvZHVjaWJpbGl0eS4NCg0KVGhlIHN5bnRheCBpcyBzaW1pbGFyIGlzIHRoZSBzYW1lIGFzIGB3cml0ZV9jc3ZgLCBidXQgdXNlcyB0aGUgZnVuY3Rpb24gYHNhdmUoKWA6DQoNCmBgYHtyfQ0Kc2F2ZShqc19kYXRhLCBmaWxlPSJkYXRhL2NsZWFuLWNvbHMuUkRhdGEiKQ0KYGBgDQoNCjxicj4NCg0KOjo6bm90ZQ0KV2hlbiBvcGVuaW5nIGFuIGAuUkRhdGFgIGZpbGUsIGluc3RlYWQgb2YgdXNpbmcgYHJlYWRfY3N2KClgLCB5b3UgdXNlIHRoZSBgbG9hZCgpYCBjb21tYW5kLiAgVGhlIHN5bnRheCBpcyB0aGUgc2FtZSwgYW5kIHRvIHJlb3BlbiB0aGUgZmlsZSB5b3UganVzdCBzYXZlZCB3b3VsZCBsb29rIGxpa2UgdGhpczoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQpgbG9hZCgiZGF0YS9jbGVhbi1jb2xzLlJEYXRhIilgDQpgYGANCg0KDQo6OjoNCg0KDQoNCg0K