EB3I n1 2025 scRNAseq
-
Connexion at OoD
R/Rstudio : theory

-





1 PREAMBLE

1.1 Purpose of this session

This file describes the theory inside R/Rstudio to perform data analysis, especially the first part of the single cell RNAseq data analysis training course for the EBAII n1 2025, covering these steps :

  • Speaking in R
  • Writing code in Rstudio
  • Think about what you want with which tools?

1.2 What should you run ?

  • This training presentation, written in Rmarkdown, contains many chunks ( = code blocks)

  • You do not need to run them all !

  • Chunks follow a color scheme :

1.2.1 Chunks you ARE expected to run :

# chunk_run

## Example of a chunk to run
getwd()
Show output
[1] "/media/mna_bioinfo/MNA2_Stockage/EBAII"




2 Start OpenOnDemand



3 Start Rstudio

  • Create a Rstudio session with the right resource requirements, thanks to the cheat sheet.

3.1 First sight

  • A : global functions tools
  • B : Quick-launch functions 1
  • C : Script pane
  • D : Console pane
  • E : Monitoring console
  • F : Work folder
  • G : Work session
  • H : Quick-launch function 2
  • I : Environment console pane
  • J : Environment monitoring console
  • K : Multi-widgets interface
  • L : Quick-launch function 3

3.2 Console Pane (D + E)

This is a standard R console. Open your bash terminal, enter the following command: R, and you will get the same console.

Warning: Here, we are in a RStudio session powered by the IFB. Your local RStudio might differ: the version of R, the list of available packages, etc. On your local machine, RStudio console will match with the R available in your terminal.

Let’s try to enter the command print():

print("Hello World")
Show output
[1] "Hello World"

We just used a function, called print. This function tries to print on screen everything provided between parenthesis ( and ). In this particular case, we gave the character string “Hello World”, and the function print successfully printed it on screen !

Now click on Session -> Save Workspace as and save the current work space. What happened in the R console pane? You saw it! A command has been automatically written. For me, it is:

save.image("./SingleCell.RData")

When you need help with R, whether on a function error, on a script result or anything alike, please save your work space and send-it to your favorite R-developer. This contains everything you did in your session.

Info: There is a syntax coloration, there is a good autocompletion and parameter suggestion. If I ever see anyone writing down a complete command without typing the tabulation key, then I’ll have to steal their dessert. And I’m always hungry enough for desserts.

3.3 Environment/History/Connection/Git (F + G + H + I + J)

3.3.1 Environment

This pane has three tabs: Environment, History and Connections.

Environment lists every single variable, object or data loaded in R. This includes only what you typed yourself and does not include environment variables. Example; in you console pane, enter the following command:

zero <- 0  # May also be written zero = 0

What happened in the Environment pane ? You’re right: a variable is now available!

When a more complex object is declared in your work space, then some general information may be available. Example:

small_table <- data.frame("col_a"=c(1, 3), "col_b"=c(2, 4))

You can see the dataframe. Click on it to have a preview of the data it contains, then click on the light-blue arrow have a deeper insight of its content:

Now click on Session -> Clear Work space: and see your work disappear. This action cannot be undone. While it is useful to clear one work space from time to time in order to avoid name space collisions, it is better to save your work space before.

3.4 History

This tab is quite important: while you test and search in the console, your history keeps a track of each command line you entered. This will definitely help you to build your scripts, to pass your command lines to your coworkers, and to revert possible unfortunate errors.

Each history is related to a session. You may see many commands in your history. Some of them are not even listed in your console. R Studio in writes there every command, even the ones that were masked for the sake of your eyes (knitting commands, display commands, help commands, etc.)

Your history has a size limit. This limit is set by an environment variable called R_HISTSIZE (standing for: R History Size). It may be checked with the function Sys.getenv() and set with the function Sys.setenv():

3.5 The Help/Plot/Packages/File pane (K + L)

3.5.1 Help

This is maybe the most important pane of your R Studio. THIS is the difference between R Studio and another code editor. Search for any function here and not on the internet. This pane shows you the available help for YOUR version of R, YOUR version of a given package.

Different versions may have different default parameters and interfaces. Please be sure over the internet, to copy and type commands that are not harmfull for your computer.

3.5.1.1 How find help for one object ?

?data.frame
??data.frame

3.5.2 File

Just like any file explorer, we can move accross directories, create folders and file, delete them, etc.

Where am I ?

getwd()
Show output
[1] "/media/mna_bioinfo/MNA2_Stockage/EBAII"

Or use the function dir.create():

dir.create("~/introR/intro_R")

You should change your working directory right now:

Or use setwd():

3.5.3 The script pane (C)

This is where you write your R scripts. This also accepts other languages (e.g. bash, python, …), but R Studio shines for its R integration.

Please, please ! Write your commands in the Script pane, then execute them by hitting CTRL + Enter. This is very much like your lab-workbook: the history pane only keeps a limited number of function in memory while this script keeps your commands in a file on your disk. You may share it, edit it, comment it, etc.

TLDR – Too Long Didn’t Read

Graphic interface presentation :

Write command lines in Script pane
Execute command lines by hitting CTRL + Enter from script pane et see them in the console.
Have a look at the environment and history in case on the upper right pane
Search for help in the lower right pane.


4 R

4.1 Speaking R

4.1.1 Vocabulary

A variable is a container or a content named. A container is an object. A content is an element. Inside elements, we distinguish between data and metadata. We manipulate elements inside an object with functions.

We talk in R with commands to do a task in application of rules and in following best-practice guidelines. The process is not linear : it can be modified by different control structures. The whole describes an algorithm.

In the good conditions, we use a “work plane” as an IDE as Rstudio. Object have properties : types, data structure, dimension, class, functions

4.1.2 Packages

4.1.2.1 … in IFB core cluster

You may install a new package on your local computer. You shall not do it on a cluster. The IFB core cluster you are working on today is shared and highly valuable ; no one can install anything besides the official maintainers.

The following lines are written for instruction purpose and should not be used on IFB core cluster.

4.1.2.2 … in local

A package is a collection of functions organizing to make a job in a field We can show these functions in cheat-sheets or in a tutorial. ### How calling packages ? There are 2 methods to call a package : library() and require()

library load in global environment and stop process if package don’t installed Perfect at the start of a script

#library(Seurat)

require load in global environment and return TRUE/FALSE if package don’t installed Perfect for functions

#require(Seurat)

4.1.3 How installing packages ?

You may install a new package on your local computer. You shall not do it on a cluster. The IFB core cluster you are working on today is shared and highly valuable ; no one can install anything besides the official maintainers.

The following lines are written for instruction purpose and should not be used on IFB core cluster.

There are different functions to install a package :

  • classic
#install.packages(Seurat)

This will raise a prompt asking for simple questions : where to download from (choose somewhere in France), whether to update other packages or not.

Do not be afraid by the large amount of things prompted in the console and let R do the trick.

Alternatively, you can click Tool -> Install Packages in RStudio.

You can list installed packages with installed.packages(), and find for packages that can be updates with old.packages(). These packages can be updated with update.packages().

While the function install.packages() searches packages in the common R package list, many bioinformatics packages are available on other shared packages warehouses. Just like AppleStore and GoogleStore do not have the same applications on mobile, R has multiple sources for its packages. You need to know one of them, and one only Bioconductor.

  • bioconductor

  • devtools

  • remotes

Today, a package has dependencies that are also packages

4.1.4 Few usefull packages for general use

4.1.5 … And in single cell/nuclei/spatial transcriptomic

4.2 Types

As any language, we use different symbols to different concepts :

  • numbers (integer and real)
  • character
  • boolean (TRUE or FALSE)
  • date
  • factor

4.2.1 Numbers

val1 <- 3

With the code above, the number 3 is stored in a variable called “val1”. You can do this in R with anything. Literally anything. Whole files, pipelines, images, anything.

Maths in R works the same as your regular calculator:

3 + val1 # Add
Show output
[1] 6
3 + val1 # Add
Show output
[1] 6
4 / 2 # Divide
Show output
[1] 2
3 * 4 # Multiply
Show output
[1] 12
7 %/% 2 # Floor division
Show output
[1] 3

4.2.2 Characters

Characters are delimited with quotes, either double " or single ' :

val2 <- "4"
val5 <- '5'

# The example below is a very good example of
# how to never ever name a variable.
<- "happy"

Mathematics does not work with characters at all … Try the following:

You can try to turn characters in numbers with the function: as.numeric:

as.numeric("4") + 1
Show output
[1] 5
as.numeric(val2) + 1
Show output
[1] 5

A function is a R command that is followed by parenthesis ( and ). Between these parenthesis, we enter arguments. Use the help pane to have information about the list of arguments expected and/or understood by a given function.

As said previously, you can store any of the previously typed commands in a variable:

val4 <- as.numeric("4") + 1
val5 <- 1 + (0.5 * 2)
print(val5)
Show output
[1] 2

Please! Please! Give your variable a name understandable by humans. I don’t want to see any of you calling their variable a, b, my_var

4.2.3 Boolean

Aside from characters and numbers, there is another very important type in R (and computer science in general): booleans. There are two boolean values : TRUE and FALSE.

3 > 4
Show output
[1] FALSE
10 < 2
Show output
[1] FALSE
5 < 10
Show output
[1] TRUE

4.2.4 Factor

Factor are similar as vector but… it’s a categorical vector.

factor_element <- factor(x = c("1","2","4","4","5","6","2","3"),
                         levels = c("1","2","3","4","5","6"))
print(factor_element)
Show output
[1] 1 2 4 4 5 6 2 3
Levels: 1 2 3 4 5 6
table(factor_element)
Show output
factor_element
1 2 3 4 5 6 
1 2 1 2 1 1 

4.3 Data Structure

To manipulate information, we conserve data in a group and it depend of the type or a combination of type

  • vector
  • matrix
  • array
  • list
  • data.frame

4.3.1 Vector

You can make vectors in R. Don’t panic, there will be no maths in this presentation.

In R, vectors are created with the function c:

vector_numbers <- c("1", "2", "3", "4", "10", "20")
print(vector_numbers)
Show output
[1] "1"  "2"  "3"  "4"  "10" "20"
is.vector(vector_numbers)
Show output
[1] TRUE

One can select an element of the vector with squared brackets [ and ]:

vector_numbers[1]
Show output
[1] "1"

One can select multiple elements of a vector with ::

vector_numbers[2:4]
Show output
[1] "2" "3" "4"

Ok ? So, vector is simply data in one dimension #### Questions

Question 1: Is there a difference between these two vectors ?

c_vector <- c("1", "2", "3", "3")
n_vector <- c( 1,   2,   3,   3 )

Question 2: Can I include both text and numbers in a vector ?

mixed_vector <- c(1, "2", 3)

4.3.2 Matrix/Array

Matrix is a table in two dimensions : row and column

mat <- matrix(1:12, nrow=3, ncol=4)
print(mat)
Show output
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12

To access in one element to cross row and column :

mat[2,3]
Show output
[1] 8

Array is a table in 3 and more dimension.

Basically, in 3D, your have a cube, in nD, your have a hypercube.

The advantage of matrices and arrays is that you can apply transformations to them, because these data structures accept only one type.

mat2 <- log(mat)
print(mat2)
Show output
          [,1]     [,2]     [,3]     [,4]
[1,] 0.0000000 1.386294 1.945910 2.302585
[2,] 0.6931472 1.609438 2.079442 2.397895
[3,] 1.0986123 1.791759 2.197225 2.484907

4.3.3 Data.frame

In R, tables are created with the function data.frame:

dataframe_numbers <- data.frame(c(1, 3), c(2, 4))
print(dataframe_numbers)
Show output
  c.1..3. c.2..4.
1       1       2
2       3       4

You can rename columns and row names respectively with function colnames() and rownames().

colnames(dataframe_numbers) <- c("Col_1_3", "Col_2_4")
rownames(dataframe_numbers) <- c("Row_1_2", "Row_3_4")
print(dataframe_numbers)
Show output
        Col_1_3 Col_2_4
Row_1_2       1       2
Row_3_4       3       4

You can access a column and a line of the data frame using squared brackets [ and ]. Use the following syntax: [row, column]. Use either the name of the row/column or its position.

# Select a row by its name
print(dataframe_numbers["Row_1_2", ])
Show output
        Col_1_3 Col_2_4
Row_1_2       1       2
# Select a row by its index
print(dataframe_numbers[1, ])
Show output
        Col_1_3 Col_2_4
Row_1_2       1       2
 # Select a column by its name
print(dataframe_numbers[, "Col_1_3"])
Show output
[1] 1 3
 # Select a column by its index
print(dataframe_numbers[, 1])
Show output
[1] 1 3
 # Select a cell in the table
print(dataframe_numbers["Row_1_2", "Col_1_3"])
Show output
[1] 1
# Select the first two rows and the first column in the table
print(dataframe_numbers[1:2, 1]) 
Show output
[1] 1 3

If you like maths, you will remember the order [row, column]. If you’re not familiar with that, then you will do like 99% of all software engineer: you will write [column, row], and you will get an error. Trust me. 99%. Remember, an error is never a problem in informatics

4.3.4 List

In R, list is a collection of others data structures.

4.3.5 Question

Question : Who is what ?

4.3.5.1 Read a table as data frame

Exercise: Use the Help pane to find how to use the function read.csv. You can find example_table.csv in /shared/projects/2538_eb3i_n1_2025/atelier_scrnaseq/TD/

Use the function read.csv to:

  1. copy and open the file ./example_table.csv in your project directory.
  2. this table has a header (TRUE).
  3. this table has row names in the column called “ensembl_gene_id”.

Let all other parameters to their default values.

Save the opened table in a variable called example_table.

Now let us explore this dataset.

We can click on environment pane :

Be careful, large table may hang your session.

Alternatively, we can use the function head which prints the first lines of a table:

example_table <- read.csv("example_table.csv")
head(example_table)
Show output
     ensembl_gene_id gene_name sample_1 sample_2 sample_3 sample_4 sample_5
1 ENSMUSG00000000001     Gnai3       22       33       24       16       24
2 ENSMUSG00000000003      Pbsn        0        0        0        0        0
3 ENSMUSG00000000028     Cdc45        5       11        8       11        9
4 ENSMUSG00000000031       H19     5483     5912     6876     4215     3200
5 ENSMUSG00000000037     Scml2        0        1        0        2        1
6 ENSMUSG00000000049      Apoh        3        3        3        2        0
  sample_6 sample_7 sample_8 sample_9 sample_10 sample_11
1       33       39       28       17        70        15
2        0        0        0        0         0         0
3        5        7        7        7        11         3
4     3187     3076     1982     1236      3282      3159
5        1        0        0        0         0         0
6        1        3        1        0         1         4
library(readxl)
example_table <- read_xlsx("example_table.xlsx")
head(example_table)
Show output
# A tibble: 6 × 13
  ensembl_gene_id    gene_name sample_1 sample_2 sample_3 sample_4 sample_5
  <chr>              <chr>     <chr>       <dbl> <chr>    <chr>       <dbl>
1 ENSMUSG00000000001 Gnai3     22             33 24       16             24
2 ENSMUSG00000000003 Pbsn      0               0 0        0               0
3 ENSMUSG00000000028 Cdc45     5              11 8        11              9
4 ENSMUSG00000000031 H19       5483         5912 6876     4215         3200
5 ENSMUSG00000000037 Scml2     0               1 0        2               1
6 ENSMUSG00000000049 Apoh      3               3 3        2               0
# ℹ 6 more variables: sample_6 <dbl>, sample_7 <chr>, sample_8 <chr>,
#   sample_9 <dbl>, sample_10 <chr>, sample_11 <chr>

The function summary describes the dataset per sample:

summary(example_table)
Show output
 ensembl_gene_id     gene_name           sample_1            sample_2      
 Length:28          Length:28          Length:28          Min.   :   0.00  
 Class :character   Class :character   Class :character   1st Qu.:   0.75  
 Mode  :character   Mode  :character   Mode  :character   Median :   7.50  
                                                          Mean   : 351.89  
                                                          3rd Qu.:  38.50  
                                                          Max.   :5912.00  
   sample_3           sample_4            sample_5          sample_6      
 Length:28          Length:28          Min.   :   0.00   Min.   :   0.00  
 Class :character   Class :character   1st Qu.:   1.75   1st Qu.:   1.00  
 Mode  :character   Mode  :character   Median :  11.50   Median :   7.50  
                                       Mean   : 285.75   Mean   : 269.43  
                                       3rd Qu.:  49.25   3rd Qu.:  49.25  
                                       Max.   :3660.00   Max.   :3187.00  
   sample_7           sample_8            sample_9       sample_10        
 Length:28          Length:28          Min.   :   0.0   Length:28         
 Class :character   Class :character   1st Qu.:   0.0   Class :character  
 Mode  :character   Mode  :character   Median :  10.5   Mode  :character  
                                       Mean   : 195.5                     
                                       3rd Qu.:  47.0                     
                                       Max.   :3278.0                     
  sample_11        
 Length:28         
 Class :character  
 Mode  :character  
                   
                   
                   

Have a look at the summary of the dataset per gene, using the function t to transpose:

head(t(example_table))
Show output
                [,1]                 [,2]                 [,3]                
ensembl_gene_id "ENSMUSG00000000001" "ENSMUSG00000000003" "ENSMUSG00000000028"
gene_name       "Gnai3"              "Pbsn"               "Cdc45"             
sample_1        "22"                 "0"                  "5"                 
sample_2        "  33"               "   0"               "  11"              
sample_3        "24"                 "0"                  "8"                 
sample_4        "16"                 "0"                  "11"                
                [,4]                 [,5]                 [,6]                
ensembl_gene_id "ENSMUSG00000000031" "ENSMUSG00000000037" "ENSMUSG00000000049"
gene_name       "H19"                "Scml2"              "Apoh"              
sample_1        "5483"               "0"                  "3"                 
sample_2        "5912"               "   1"               "   3"              
sample_3        "6876"               "0"                  "3"                 
sample_4        "4215"               "2"                  "2"                 
                [,7]                 [,8]                 [,9]                
ensembl_gene_id "ENSMUSG00000000056" "ENSMUSG00000000058" "ENSMUSG00000000078"
gene_name       "Narf"               "Cav2"               "Klf6"              
sample_1        "18"                 "54"                 "184"               
sample_2        "  24"               "  71"               " 169"              
sample_3        "33"                 "63"                 "322"               
sample_4        "45"                 "66"                 "223"               
                [,10]                [,11]                [,12]               
ensembl_gene_id "ENSMUSG00000000085" "ENSMUSG00000000088" "ENSMUSG00000000093"
gene_name       "Scmh1"              "Cox5a"              "Tbx2"              
sample_1        "154"                "2341"               "4"                 
sample_2        " 199"               "2788"               "   4"              
sample_3        "153"                "2597"               "4"                 
sample_4        "154"                "2735"               "3"                 
                [,13]                [,14]                [,15]               
ensembl_gene_id "ENSMUSG00000000094" "ENSMUSG00000000103" "ENSMUSG00000000120"
gene_name       "Tbx4"               "Zfy2"               "Ngfr"              
sample_1        "6"                  "0"                  "7"                 
sample_2        "   4"               "   0"               "   3"              
sample_3        "11"                 "0"                  "7"                 
sample_4        "5"                  "0"                  "3"                 
                [,16]                [,17]                [,18]               
ensembl_gene_id "ENSMUSG00000000125" "ENSMUSG00000000126" "ENSMUSG00000000127"
gene_name       "Wnt3"               "Wnt9a"              "Fer"               
sample_1        "0"                  "30"                 "27"                
sample_2        "   0"               "  35"               "  18"              
sample_3        "0"                  "55"                 "59"                
sample_4        "0"                  "44"                 "30.999"            
                [,19]                [,20]                [,21]               
ensembl_gene_id "ENSMUSG00000000131" "ENSMUSG00000000134" "ENSMUSG00000000142"
gene_name       "Xpo6"               "Tfe3"               "Axin2"             
sample_1        "33.001"             "34"                 "6"                 
sample_2        "  49"               "  29"               "   3"              
sample_3        "60.001"             "21"                 "11"                
sample_4        "45"                 "17"                 "10"                
                [,22]                [,23]                [,24]               
ensembl_gene_id "ENSMUSG00000000148" "ENSMUSG00000000149" "ENSMUSG00000000154"
gene_name       "Brat1"              "Gna12"              "Slc22a18"          
sample_1        "4"                  "26"                 "2"                 
sample_2        "   3"               "  34"               "   0"              
sample_3        "3"                  "21"                 "1"                 
sample_4        "6"                  "19"                 "0"                 
                [,25]                [,26]                [,27]               
ensembl_gene_id "ENSMUSG00000000157" "ENSMUSG00000000159" "ENSMUSG00000000167"
gene_name       "Itgb2l"             "Igsf5"              "Pih1d2"            
sample_1        "0"                  "0"                  "0"                 
sample_2        "   0"               "   0"               "   0"              
sample_3        "0"                  "0"                  "1"                 
sample_4        "0"                  "0"                  "0"                 
                [,28]               
ensembl_gene_id "ENSMUSG00000000168"
gene_name       "Dlat"              
sample_1        "360"               
sample_2        " 460"              
sample_3        "395"               
sample_4        "457"               
summary(t(example_table))
Show output
      V1                 V2                 V3                 V4           
 Length:13          Length:13          Length:13          Length:13         
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
      V5                 V6                 V7                 V8           
 Length:13          Length:13          Length:13          Length:13         
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
      V9                V10                V11                V12           
 Length:13          Length:13          Length:13          Length:13         
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
     V13                V14                V15                V16           
 Length:13          Length:13          Length:13          Length:13         
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
     V17                V18                V19                V20           
 Length:13          Length:13          Length:13          Length:13         
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
     V21                V22                V23                V24           
 Length:13          Length:13          Length:13          Length:13         
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
     V25                V26                V27                V28           
 Length:13          Length:13          Length:13          Length:13         
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  

4.4 Object

In R, everything is an object !

An object is a container that has a defined class of objects having properties, such as dimensions or a data structure, and contains elements having a type and a value.

4.5 Functions

Functions are script blocks created to perform specific tasks.

We already see different functions :

as.numeric() - print() - is.vector() - data.frame() - head() - summary() - t()

There are generic functions to specific class

#getS3method("print", "data.frame")
print.data.frame = function (x, ..., digits = NULL, quote = FALSE, right = TRUE, 
    row.names = TRUE, max = NULL) 
{
    n <- length(row.names(x))
    if (length(x) == 0L) {
        cat(sprintf(ngettext(n, "data frame with 0 columns and %d row", 
            "data frame with 0 columns and %d rows"), n), "\n", 
            sep = "")
    }
    else if (n == 0L) {
        print.default(names(x), quote = FALSE)
        cat(gettext("<0 rows> (or 0-length row.names)\n"))
    }
    else {
        if (is.null(max)) 
            max <- getOption("max.print", 99999L)
        if (!is.finite(max)) 
            stop("invalid 'max' / getOption(\"max.print\"): ", 
                max)
        omit <- (n0 <- max%/%length(x)) < n
        m <- as.matrix(format.data.frame(if (omit) 
            x[seq_len(n0), , drop = FALSE]
        else x, digits = digits, na.encode = FALSE))
        if (!isTRUE(row.names)) 
            dimnames(m)[[1L]] <- if (isFALSE(row.names)) 
                rep.int("", if (omit) 
                  n0
                else n)
            else row.names
        print(m, ..., quote = quote, right = right, max = max)
        if (omit) 
            cat(" [ reached 'max' / getOption(\"max.print\") -- omitted", 
                n - n0, "rows ]\n")
    }
    invisible(x)
}

We could be create new functions

calculate_toto <- function(x,y) {
  
  if (x == 0 & y == x) {
    return("tete a toto !")
  } else {
    return(x + y)
  }
}

calculate_toto(x=0,y=0)
Show output
[1] "tete a toto !"
calculate_toto(x=1,y=0)
Show output
[1] 1
calculate_toto(x=0,y=1)
Show output
[1] 1
calculate_toto(x=1,y=1)
Show output
[1] 2

R is your best friend but…sometimes, it want your gain time and arguments are “indexing” when you called function. BUT IT IS NOT RECOMMANDED

calculate_toto(0,0)
Show output
[1] "tete a toto !"

4.6 Control Structures

A script is just an execution flow.

We could be modify this flow with :

  • conditional structures

  • loop

  • intern flux structures

4.7 Special functions

Many functions are built to perform specific and optimized tasks

  • Vectorise functions
scores <- c(12, 8, 15, 7, 20)

results <- ifelse(scores >= 10, "Pass", "Fail")

print(results)
Show output
[1] "Pass" "Fail" "Pass" "Fail" "Pass"
score <- 15
if (score >= 10) {
  print("Pass")
} else {
  print("Fail")
}
Show output
[1] "Pass"
  • Iterative applicative functions
my_list <- list(a = 1:5, b = 6:10, c = 11:15)
result_lapply <- lapply(my_list, mean)
print(result_lapply)
Show output
$a
[1] 3

$b
[1] 8

$c
[1] 13
result_sapply <- sapply(my_list, mean)
print(result_sapply)
Show output
 a  b  c 
 3  8 13 
mat <- matrix(1:9, nrow = 3, byrow = TRUE)
print(mat)
Show output
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9
row_means <- apply(mat, 1, mean)
print(row_means)
Show output
[1] 2 5 8
col_means <- apply(mat, 2, mean)
print(col_means)
Show output
[1] 4 5 6
  • Functional functions
numbers <- 1:10

# Garder seulement les nombres pairs
even_numbers <- Filter(function(x) x %% 2 == 0, numbers)

print(even_numbers)
Show output
[1]  2  4  6  8 10
list1 <- list(1, 2, 3)
list2 <- list(10, 20, 30)

# Ajouter les éléments correspondants
result <- Map(function(x, y) x + y, list1, list2)

print(result)
Show output
[[1]]
[1] 11

[[2]]
[1] 22

[[3]]
[1] 33

4.8 Saves

Rstudio are two formats : .rds and .Rdata

4.8.1 Save

While working on your projects and leaning this week, you will process datasets in R. The results of these analyses will be stored on variables. This means, that when you close RStudio, some of this work might be lost.

We already saw the function save.image() to save a complete copy of your working environment.

However, you can save only the content of a give variable. This is useful when you want to save the result of a function (or a pipeline) but not the whole 5 hours of work you’ve been spending on how-to-make-that-pipeline-work-correctly.

The format is called: RDS for R Data Serialization. This is done with the function saveRDS():

saveRDS(object = example_table, file = "example_table.RDS")

4.8.2 Load

You can also load a RDS into a variable. This is useful when you receive a RDS from a coworker, or you’d like to keep going your work from a saved point. This is done with the function readRDS():

example_table <- readRDS(file = "example_table.RDS")
head(example_table)
Show output
# A tibble: 6 × 13
  ensembl_gene_id    gene_name sample_1 sample_2 sample_3 sample_4 sample_5
  <chr>              <chr>     <chr>       <dbl> <chr>    <chr>       <dbl>
1 ENSMUSG00000000001 Gnai3     22             33 24       16             24
2 ENSMUSG00000000003 Pbsn      0               0 0        0               0
3 ENSMUSG00000000028 Cdc45     5              11 8        11              9
4 ENSMUSG00000000031 H19       5483         5912 6876     4215         3200
5 ENSMUSG00000000037 Scml2     0               1 0        2               1
6 ENSMUSG00000000049 Apoh      3               3 3        2               0
# ℹ 6 more variables: sample_6 <dbl>, sample_7 <chr>, sample_8 <chr>,
#   sample_9 <dbl>, sample_10 <chr>, sample_11 <chr>

But there are other solutions :

  • fst, qs, feather, parquet
  • csv, tsv, xlsx, yaml, json
  • SQLite, DuckDB, HDF5, MonetDB Lite, Feather IPC/Arrow IPC streams,
  • gz, bz2, xz, zip
  • binaire

4.9 Help

Directly in the package documentation in Help pane or :

?print
??print

4.10 Writing code in Rstudio

Ok, it’s time to write R code. But how do you do that ? Like a writing a book !

Best practises :

###############################################################################
# Script name : analysis_pipeline.R
# Author      : Your Name
# Date        : 2025-11-15
# Purpose     : Example of clean R script structure
###############################################################################

########################
# 0. Load packages ----
########################
########################
# 1. Define parameters ----
########################
########################
# 2. Define custom functions ----
########################
########################
# 3. Load data ----
########################
########################
# 4. Data cleaning ----
########################
########################
# 5. Analysis ----
########################
########################
# 6. Visualizations ----
########################
########################
# 7. Save outputs ----
########################


LS0tCnRpdGxlOiAiPENFTlRFUj5FQjNJIG4xIDIwMjUgc2NSTkFzZXE8QlI+LTxCUj4gPEI+Q29ubmV4aW9uIGF0IE9vRFxuXG5cblIvUnN0dWRpbyA6IHRoZW9yeTwvQj48QlI+LTxCUj48L0NFTlRFUj4iCmRhdGU6ICIyMDI1LTE2LTIxLjIyIgphdXRob3I6CiAgLSBuYW1lOiAiRUJBSUkgbjEgc2NSTkFzZXEgVGVhbSIKICAtIG5hbWU6ICJXaWxsaWFtIEpBUkFTU0lFUiIKICAgIGVtYWlsOiAidy5qYXJhc3NpZXJAZ21haWwuY29tIgogIC0gbmFtZTogIkVtaWxpZSBEUk9VSU5FQVUiCiAgICBlbWFpbDogImVtaWxpZS5kcm91aW5lYXVAY2VhLmZyIgogIC0gbmFtZTogIlRoaWJhdWx0IERBWVJJUyIKICAgIGVtYWlsOiAidGhpYmF1bHQuZGF5cmlzQGd1c3RhdmVyb3Vzc3kuZnIiCgpvdXRwdXQ6CiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICBmaWdfd2lkdGg6IDgKICAgIGZpZ19oZWlnaHQ6IDYKICAgIGhpZ2hsaWdodDogdGFuZ28gICMjIFRoZW1lIGZvciB0aGUgY29kZSBjaHVua3MKICAgIGVtYmVkX2ZvbnRzOiBUUlVFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUgICMjIEFkZHMgbnVtYmVyIHRvIGhlYWRlcnMgKHNlY3Rpb25zKQogICAgdGhlbWU6IGZsYXRseSAgIyMgQ1NTIHRoZW1lIGZvciB0aGUgSFRNTCBwYWdlCiAgICBjb2xsYXBzZWQ6IHRydWUgICMjIEJ5IGRlZmF1bHQsIHRoZSBUT0MgaXMgZm9sZGVkCiAgICB0b2NfZGVwdGg6IDMKICAgIHNtb290aF9zY3JvbGw6IHRydWUgIyMgU21vb3RoIHNjcm9sbCBvZiB0aGUgSFRNTCBwYWdlCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZSAjIyBJbmNsdWRlcyBhbGwgcGxvdHMvaW1hZ2VzIHdpdGhpbiB0aGUgSFRNTAogICAgY29kZV9kb3dubG9hZDogdHJ1ZSAjIyBBZGRzIGEgYnV0dG9uIHRvIGRvd25sb2FkIHRoZSBSbWQKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgdGh1bWJuYWlsczogZmFsc2UKICAgIGxpZ2h0Ym94OiB0cnVlCiAgICBmaWdfY2FwdGlvbjogZmFsc2UKICAgIGdhbGxlcnk6IHRydWUKICAgIHVzZV9ib29rZG93bjogdHJ1ZQphbHdheXNfYWxsb3dfaHRtbDogdHJ1ZSAjIyBBbGxvdyBwbGFpbiBIVE1MIGNvZGUgaW4gdGhlIFJtZAplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgo8IS0tIGtuaXQgc2V0dXAgLS0+CgpgYGB7ciBrbml0X3NldHVwLCBlY2hvID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwgICAgICAgICMgUHJpbnQgdGhlIGNvZGUKICBldmFsID0gVFJVRSwgICAgICAgICMgUnVuIGNvbW1hbmQgbGluZXMKICBtZXNzYWdlID0gRkFMU0UsICAgICMgUHJpbnQgbWVzc2FnZXMKICBwcm9tcHQgPSBGQUxTRSwgICAgICMgRG8gbm90IGRpc3BsYXkgcHJvbXB0CiAgY29tbWVudCA9IE5BLCAgICAgICAjIE5vIGNvbW1lbnRzIG9uIHRoaXMgc2VjdGlvbgogIHdhcm5pbmcgPSBGQUxTRSwgICAgIyBEaXNwbGF5IHdhcm5pbmdzCiAgdGlkeSA9IEZBTFNFLAogIGZpZy5hbGlnbj0iY2VudGVyIiwgCiAgIyByZXN1bHRzID0gJ2hpZGUnLAogIHdpZHRoID0gMTAwICAgICAgICMgTnVtYmVyIG9mIGNoYXJhY3RlcnMgcGVyIGxpbmUKKQpgYGAKCjwhLS0gQ1NTIHRvIGNvbG9yIGNodW5rcyBhbmQgb3V0cHV0cyAtLT4KCmBgYHtjc3MsIGVjaG89RkFMU0V9Ci5ub3RydW4gewogIGJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JleSAhaW1wb3J0YW50OwogIGJvcmRlcjogM3B4IHNvbGlkIGJsYWNrICFpbXBvcnRhbnQ7Cn0KLm5vdHJ1bm8gewogIGJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JleSAhaW1wb3J0YW50OwogIGNvbG9yIDogYmxhY2sgIWltcG9ydGFudDsKfQoucXVlc3Rpb24gewogIGJhY2tncm91bmQtY29sb3I6IGFxdWFtYXJpbmUgIWltcG9ydGFudDsKICBjb2xvciA6IGJsYWNrICFpbXBvcnRhbnQ7CiAgYm9yZGVyOiAzcHggc29saWQgbGltZWdyZWVuICFpbXBvcnRhbnQ7Cn0KLnF1ZXN0aW9ubyB7CiAgYmFja2dyb3VuZC1jb2xvcjogYXF1YW1hcmluZSAhaW1wb3J0YW50OwogIGNvbG9yIDogYmxhY2sgIWltcG9ydGFudDsKfQouYW5zd2VyIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiBuYXZham93aGl0ZSAhaW1wb3J0YW50OwogIGJvcmRlcjogM3B4IHNvbGlkIGJyb3duICFpbXBvcnRhbnQ7Cn0KLmFuc3dlcm8gewogIGJhY2tncm91bmQtY29sb3I6IG5hdmFqb3doaXRlICFpbXBvcnRhbnQ7CiAgY29sb3IgOiBibGFjayAhaW1wb3J0YW50Owp9Ci5iZXlvbmQgewogIGJhY2tncm91bmQtY29sb3I6IHZpb2xldCAhaW1wb3J0YW50OwogIGJvcmRlcjogM3B4IHNvbGlkIHB1cnBsZSAhaW1wb3J0YW50Owp9Ci5iZXlvbmRvIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiB2aW9sZXQgIWltcG9ydGFudDsKICBjb2xvciA6IGJsYWNrICFpbXBvcnRhbnQ7Cn0KYGBgCgo8IS0tIEhvb2sgdG8gaGFuZGxlIGNvZGUgYmxvY2tzIG91dHB1dCBmb2xkaW5nIC0tPgoKYGBge3Iga25pdF9ob29rLCBlY2hvID0gRkFMU0V9Cmhvb2tzID0ga25pdHI6OmtuaXRfaG9va3MkZ2V0KCkKaG9va19mb2xkYWJsZSA9IGZ1bmN0aW9uKHR5cGUpIHsKICBmb3JjZSh0eXBlKQogIGZ1bmN0aW9uKHgsIG9wdGlvbnMpIHsKICAgIHJlcyA9IGhvb2tzW1t0eXBlXV0oeCwgb3B0aW9ucykKICAgIAogICAgaWYgKGlzRkFMU0Uob3B0aW9uc1tbcGFzdGUwKCJmb2xkLiIsIHR5cGUpXV0pKSByZXR1cm4ocmVzKQogICAgCiAgICBwYXN0ZTAoCiAgICAgICI8ZGV0YWlscz48c3VtbWFyeT5TaG93ICIsIHR5cGUsICI8L3N1bW1hcnk+XG5cbiIsCiAgICAgIHJlcywKICAgICAgIlxuXG48L2RldGFpbHM+IgogICAgKQogIH0KfQprbml0cjo6a25pdF9ob29rcyRzZXQoCiAgb3V0cHV0ID0gaG9va19mb2xkYWJsZSgib3V0cHV0IiksCiAgcGxvdCA9IGhvb2tfZm9sZGFibGUoInBsb3QiKQopCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCjxjZW50ZXI+IVtdKGViM2lfYmFubmVyLnBuZyk8L2NlbnRlcj4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIFBSRUFNQkxFCgojIyBQdXJwb3NlIG9mIHRoaXMgc2Vzc2lvbgoKVGhpcyBmaWxlIGRlc2NyaWJlcyB0aGUgdGhlb3J5IGluc2lkZSBSL1JzdHVkaW8gdG8gcGVyZm9ybSBkYXRhCmFuYWx5c2lzLCBlc3BlY2lhbGx5IHRoZSAqKmZpcnN0IHBhcnQqKiBvZiB0aGUgKipzaW5nbGUgY2VsbCBSTkFzZXEqKgpkYXRhIGFuYWx5c2lzIHRyYWluaW5nIGNvdXJzZSBmb3IgdGhlICoqRUJBSUkgbjEgMjAyNSoqLCBjb3ZlcmluZyB0aGVzZQpzdGVwcyA6CgotICAgKipTcGVha2luZyBpbiBSKioKLSAgICoqV3JpdGluZyBjb2RlIGluIFJzdHVkaW8qKgotICAgKipUaGluayBhYm91dCB3aGF0IHlvdSB3YW50IHdpdGggd2hpY2ggdG9vbHM/KioKCiMjIFdoYXQgc2hvdWxkIHlvdSBydW4gPwoKLSAgIFRoaXMgdHJhaW5pbmcgcHJlc2VudGF0aW9uLCB3cml0dGVuIGluIFJtYXJrZG93biwgY29udGFpbnMgKiptYW55KioKICAgIGNodW5rcyAoID0gY29kZSBibG9ja3MpCgotICAgWW91ICoqZG8gbm90IG5lZWQgdG8qKiBydW4gdGhlbSBhbGwgIQoKLSAgIENodW5rcyBmb2xsb3cgYSAqKmNvbG9yIHNjaGVtZSoqIDoKCiMjIyBDaHVua3MgeW91ICoqQVJFKiogZXhwZWN0ZWQgdG8gcnVuIDoKCmBgYHtyIGNodW5rX3J1bn0KIyBjaHVua19ydW4KCiMjIEV4YW1wbGUgb2YgYSBjaHVuayB0byBydW4KZ2V0d2QoKQoKYGBgCgo8YnI+CgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBTdGFydCBPcGVuT25EZW1hbmQKCi0gICBVc2luZyB0aGUgW09wZW5PbkRlbWFuZCBjaGVhdAogICAgc2hlZXRdKGh0dHBzOi8vaWZiLWVsaXhpcmZyLmdpdGh1Yi5pby9FQkFJSS8yMDIzL2ViYWlpbjEvU2luZ2xlQ2VsbC8yMDI0X1REX09wZW5PbkRlbWFuZC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9Cgo8Y2VudGVyPiFbXShjb25uZWN0aW9uX29vZC5wbmcpPC9jZW50ZXI+Cgo8Y2VudGVyPiFbXShkZXNrdG9wX29vZC5wbmcpPC9jZW50ZXI+CgotICAgQ29ubmVjdCB0byB0aGUgW09wZW5PbkRlbWFuZAogICAgcG9ydGFsXShodHRwczovL29uZGVtYW5kLmNsdXN0ZXIuZnJhbmNlLWJpb2luZm9ybWF0aXF1ZS5mcil7dGFyZ2V0PSJfYmxhbmsifQoKPGNlbnRlcj4hW10ocGFyYW1ldHJhZ2VfcnN0dWRpb18yX3VwLnBuZyk8L2NlbnRlcj4KPGNlbnRlcj4hW10ocGFyYW1ldHJhZ2VfcnN0dWRpb18yX2RuLnBuZyk8L2NlbnRlcj4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIFN0YXJ0IFJzdHVkaW8KCi0gICAqKkNyZWF0ZSBhIFJzdHVkaW8gc2Vzc2lvbioqIHdpdGggdGhlIHJpZ2h0IHJlc291cmNlIHJlcXVpcmVtZW50cywKICAgIHRoYW5rcyB0byB0aGUgY2hlYXQgc2hlZXQuCgojIyBGaXJzdCBzaWdodAoKPGNlbnRlcj4hW10ocnN0dWRpb19maXJzdF9zaWdodC5wbmcpPC9jZW50ZXI+CgotICAgQSA6IGdsb2JhbCBmdW5jdGlvbnMgdG9vbHMKLSAgIEIgOiBRdWljay1sYXVuY2ggZnVuY3Rpb25zIDEKLSAgIEMgOiBTY3JpcHQgcGFuZQotICAgRCA6IENvbnNvbGUgcGFuZQotICAgRSA6IE1vbml0b3JpbmcgY29uc29sZQotICAgRiA6IFdvcmsgZm9sZGVyCi0gICBHIDogV29yayBzZXNzaW9uCi0gICBIIDogUXVpY2stbGF1bmNoIGZ1bmN0aW9uIDIKLSAgIEkgOiBFbnZpcm9ubWVudCBjb25zb2xlIHBhbmUKLSAgIEogOiBFbnZpcm9ubWVudCBtb25pdG9yaW5nIGNvbnNvbGUKLSAgIEsgOiBNdWx0aS13aWRnZXRzIGludGVyZmFjZQotICAgTCA6IFF1aWNrLWxhdW5jaCBmdW5jdGlvbiAzCgojIyBDb25zb2xlIFBhbmUgKEQgKyBFKQoKVGhpcyBpcyBhIHN0YW5kYXJkIFIgY29uc29sZS4gT3BlbiB5b3VyIGJhc2ggdGVybWluYWwsIGVudGVyIHRoZQpmb2xsb3dpbmcgY29tbWFuZDogUiwgYW5kIHlvdSB3aWxsIGdldCB0aGUgc2FtZSBjb25zb2xlLgoKYGBgICAgICAgICAgCldhcm5pbmc6IEhlcmUsIHdlIGFyZSBpbiBhIFJTdHVkaW8gc2Vzc2lvbiBwb3dlcmVkIGJ5IHRoZSBJRkIuIFlvdXIgbG9jYWwgUlN0dWRpbyBtaWdodCBkaWZmZXI6IHRoZSB2ZXJzaW9uIG9mIFIsIHRoZSBsaXN0IG9mIGF2YWlsYWJsZSBwYWNrYWdlcywgZXRjLiBPbiB5b3VyIGxvY2FsIG1hY2hpbmUsIFJTdHVkaW8gY29uc29sZSB3aWxsIG1hdGNoIHdpdGggdGhlIFIgYXZhaWxhYmxlIGluIHlvdXIgdGVybWluYWwuCmBgYAoKTGV04oCZcyB0cnkgdG8gZW50ZXIgdGhlIGNvbW1hbmQgcHJpbnQoKToKCmBgYHtyIGhlbGxvd29ybGR9CnByaW50KCJIZWxsbyBXb3JsZCIpCmBgYAoKV2UganVzdCB1c2VkIGEgZnVuY3Rpb24sIGNhbGxlZCBwcmludC4gVGhpcyBmdW5jdGlvbiB0cmllcyB0byBwcmludCBvbgpzY3JlZW4gZXZlcnl0aGluZyBwcm92aWRlZCBiZXR3ZWVuIHBhcmVudGhlc2lzICggYW5kICkuIEluIHRoaXMKcGFydGljdWxhciBjYXNlLCB3ZSBnYXZlIHRoZSBjaGFyYWN0ZXIgc3RyaW5nICJIZWxsbyBXb3JsZCIsIGFuZCB0aGUKZnVuY3Rpb24gcHJpbnQgc3VjY2Vzc2Z1bGx5IHByaW50ZWQgaXQgb24gc2NyZWVuICEKCk5vdyBjbGljayBvbiBTZXNzaW9uIC1cPiBTYXZlIFdvcmtzcGFjZSBhcyBhbmQgc2F2ZSB0aGUgY3VycmVudCB3b3JrCnNwYWNlLiBXaGF0IGhhcHBlbmVkIGluIHRoZSBSIGNvbnNvbGUgcGFuZT8gWW91IHNhdyBpdCEgQSBjb21tYW5kIGhhcwpiZWVuIGF1dG9tYXRpY2FsbHkgd3JpdHRlbi4gRm9yIG1lLCBpdCBpczoKCmBgYHtyIGZpcnN0fQpzYXZlLmltYWdlKCIuL1NpbmdsZUNlbGwuUkRhdGEiKQpgYGAKCldoZW4geW91IG5lZWQgaGVscCB3aXRoIFIsIHdoZXRoZXIgb24gYSBmdW5jdGlvbiBlcnJvciwgb24gYSBzY3JpcHQKcmVzdWx0IG9yIGFueXRoaW5nIGFsaWtlLCBwbGVhc2Ugc2F2ZSB5b3VyIHdvcmsgc3BhY2UgYW5kIHNlbmQtaXQgdG8KeW91ciBmYXZvcml0ZSBSLWRldmVsb3Blci4gVGhpcyBjb250YWlucyBldmVyeXRoaW5nIHlvdSBkaWQgaW4geW91cgpzZXNzaW9uLgoKYGBgICAgICAgICAgCkluZm86IFRoZXJlIGlzIGEgc3ludGF4IGNvbG9yYXRpb24sIHRoZXJlIGlzIGEgZ29vZCBhdXRvY29tcGxldGlvbiBhbmQgcGFyYW1ldGVyIHN1Z2dlc3Rpb24uIElmIEkgZXZlciBzZWUgYW55b25lIHdyaXRpbmcgZG93biBhIGNvbXBsZXRlIGNvbW1hbmQgd2l0aG91dCB0eXBpbmcgdGhlIHRhYnVsYXRpb24ga2V5LCB0aGVuIEnigJlsbCBoYXZlIHRvIHN0ZWFsIHRoZWlyIGRlc3NlcnQuIEFuZCBJ4oCZbSBhbHdheXMgaHVuZ3J5IGVub3VnaCBmb3IgZGVzc2VydHMuCmBgYAoKIyMgRW52aXJvbm1lbnQvSGlzdG9yeS9Db25uZWN0aW9uL0dpdCAoRiArIEcgKyBIICsgSSArIEopCgojIyMgRW52aXJvbm1lbnQKClRoaXMgcGFuZSBoYXMgdGhyZWUgdGFiczogRW52aXJvbm1lbnQsIEhpc3RvcnkgYW5kIENvbm5lY3Rpb25zLgoKRW52aXJvbm1lbnQgbGlzdHMgZXZlcnkgc2luZ2xlIHZhcmlhYmxlLCBvYmplY3Qgb3IgZGF0YSBsb2FkZWQgaW4gUi4KVGhpcyBpbmNsdWRlcyBvbmx5IHdoYXQgeW91IHR5cGVkIHlvdXJzZWxmIGFuZCBkb2VzIG5vdCBpbmNsdWRlCmVudmlyb25tZW50IHZhcmlhYmxlcy4gRXhhbXBsZTsgaW4geW91IGNvbnNvbGUgcGFuZSwgZW50ZXIgdGhlIGZvbGxvd2luZwpjb21tYW5kOgoKYGBge3Igc2Vjb25kfQp6ZXJvIDwtIDAgICMgTWF5IGFsc28gYmUgd3JpdHRlbiB6ZXJvID0gMApgYGAKCldoYXQgaGFwcGVuZWQgaW4gdGhlIEVudmlyb25tZW50IHBhbmUgPyBZb3XigJlyZSByaWdodDogYSB2YXJpYWJsZSBpcyBub3cKYXZhaWxhYmxlIQoKPGNlbnRlcj4hW10oZW52aXJvbm1lbnQucG5nKTwvY2VudGVyPgoKV2hlbiBhIG1vcmUgY29tcGxleCBvYmplY3QgaXMgZGVjbGFyZWQgaW4geW91ciB3b3JrIHNwYWNlLCB0aGVuIHNvbWUKZ2VuZXJhbCBpbmZvcm1hdGlvbiBtYXkgYmUgYXZhaWxhYmxlLiBFeGFtcGxlOgoKYGBge3IgdGhpcmR9CnNtYWxsX3RhYmxlIDwtIGRhdGEuZnJhbWUoImNvbF9hIj1jKDEsIDMpLCAiY29sX2IiPWMoMiwgNCkpCmBgYAoKWW91IGNhbiBzZWUgdGhlIGRhdGFmcmFtZS4gQ2xpY2sgb24gaXQgdG8gaGF2ZSBhIHByZXZpZXcgb2YgdGhlIGRhdGEgaXQKY29udGFpbnMsIHRoZW4gY2xpY2sgb24gdGhlIGxpZ2h0LWJsdWUgYXJyb3cgaGF2ZSBhIGRlZXBlciBpbnNpZ2h0IG9mCml0cyBjb250ZW50OgoKPGNlbnRlcj4hW10oZGF0YWZyYW1lLnBuZyk8L2NlbnRlcj4KCk5vdyBjbGljayBvbiBTZXNzaW9uIC1cPiBDbGVhciBXb3JrIHNwYWNlOiBhbmQgc2VlIHlvdXIgd29yayBkaXNhcHBlYXIuClRoaXMgYWN0aW9uIGNhbm5vdCBiZSB1bmRvbmUuIFdoaWxlIGl0IGlzIHVzZWZ1bCB0byBjbGVhciBvbmUgd29yayBzcGFjZQpmcm9tIHRpbWUgdG8gdGltZSBpbiBvcmRlciB0byBhdm9pZCBuYW1lIHNwYWNlIGNvbGxpc2lvbnMsIGl0IGlzIGJldHRlcgp0byBzYXZlIHlvdXIgd29yayBzcGFjZSBiZWZvcmUuCgojIyBIaXN0b3J5Cgo8Y2VudGVyPiFbXShoaXN0b3J5LnBuZyk8L2NlbnRlcj4KClRoaXMgdGFiIGlzIHF1aXRlIGltcG9ydGFudDogd2hpbGUgeW91IHRlc3QgYW5kIHNlYXJjaCBpbiB0aGUgY29uc29sZSwKeW91ciBoaXN0b3J5IGtlZXBzIGEgdHJhY2sgb2YgZWFjaCBjb21tYW5kIGxpbmUgeW91IGVudGVyZWQuIFRoaXMgd2lsbApkZWZpbml0ZWx5IGhlbHAgeW91IHRvIGJ1aWxkIHlvdXIgc2NyaXB0cywgdG8gcGFzcyB5b3VyIGNvbW1hbmQgbGluZXMgdG8KeW91ciBjb3dvcmtlcnMsIGFuZCB0byByZXZlcnQgcG9zc2libGUgdW5mb3J0dW5hdGUgZXJyb3JzLgoKRWFjaCBoaXN0b3J5IGlzIHJlbGF0ZWQgdG8gYSBzZXNzaW9uLiBZb3UgbWF5IHNlZSBtYW55IGNvbW1hbmRzIGluIHlvdXIKaGlzdG9yeS4gU29tZSBvZiB0aGVtIGFyZSBub3QgZXZlbiBsaXN0ZWQgaW4geW91ciBjb25zb2xlLiBSIFN0dWRpbyBpbgp3cml0ZXMgdGhlcmUgZXZlcnkgY29tbWFuZCwgZXZlbiB0aGUgb25lcyB0aGF0IHdlcmUgbWFza2VkIGZvciB0aGUgc2FrZQpvZiB5b3VyIGV5ZXMgKGtuaXR0aW5nIGNvbW1hbmRzLCBkaXNwbGF5IGNvbW1hbmRzLCBoZWxwIGNvbW1hbmRzLCBldGMuKQoKWW91ciBoaXN0b3J5IGhhcyBhIHNpemUgbGltaXQuIFRoaXMgbGltaXQgaXMgc2V0IGJ5IGFuIGVudmlyb25tZW50CnZhcmlhYmxlIGNhbGxlZCBSX0hJU1RTSVpFIChzdGFuZGluZyBmb3I6IFIgSGlzdG9yeSBTaXplKS4gSXQgbWF5IGJlCmNoZWNrZWQgd2l0aCB0aGUgZnVuY3Rpb24gU3lzLmdldGVudigpIGFuZCBzZXQgd2l0aCB0aGUgZnVuY3Rpb24KU3lzLnNldGVudigpOgoKYGBge3IgZm91cnRoLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpTeXMuZ2V0ZW52KCJSX0hJU1RTSVpFIikKU3lzLnNldGVudihSX0hJU1RTSVpFID0gbmV3X251bWJlcikKYGBgCgojIyBUaGUgSGVscC9QbG90L1BhY2thZ2VzL0ZpbGUgcGFuZSAoSyArIEwpCgojIyMgSGVscAoKVGhpcyBpcyBtYXliZSB0aGUgbW9zdCBpbXBvcnRhbnQgcGFuZSBvZiB5b3VyIFIgU3R1ZGlvLiBUSElTIGlzIHRoZQpkaWZmZXJlbmNlIGJldHdlZW4gUiBTdHVkaW8gYW5kIGFub3RoZXIgY29kZSBlZGl0b3IuIFNlYXJjaCBmb3IgYW55CmZ1bmN0aW9uIGhlcmUgYW5kIG5vdCBvbiB0aGUgaW50ZXJuZXQuIFRoaXMgcGFuZSBzaG93cyB5b3UgdGhlIGF2YWlsYWJsZQpoZWxwIGZvciBZT1VSIHZlcnNpb24gb2YgUiwgWU9VUiB2ZXJzaW9uIG9mIGEgZ2l2ZW4gcGFja2FnZS4KCkRpZmZlcmVudCB2ZXJzaW9ucyBtYXkgaGF2ZSBkaWZmZXJlbnQgZGVmYXVsdCBwYXJhbWV0ZXJzIGFuZCBpbnRlcmZhY2VzLgpQbGVhc2UgYmUgc3VyZSBvdmVyIHRoZSBpbnRlcm5ldCwgdG8gY29weSBhbmQgdHlwZSBjb21tYW5kcyB0aGF0IGFyZSBub3QKaGFybWZ1bGwgZm9yIHlvdXIgY29tcHV0ZXIuCgo8Y2VudGVyPiFbXShoZWxwX2RhdGFmcmFtZS5wbmcpPC9jZW50ZXI+CgojIyMjIEhvdyBmaW5kIGhlbHAgZm9yIG9uZSBvYmplY3QgPwoKYGBge3IgaGVscDF9Cj9kYXRhLmZyYW1lCmBgYAoKYGBge3IgaGVscDJ9Cj8/ZGF0YS5mcmFtZQpgYGAKCiMjIyBGaWxlCgpKdXN0IGxpa2UgYW55IGZpbGUgZXhwbG9yZXIsIHdlIGNhbiBtb3ZlIGFjY3Jvc3MgZGlyZWN0b3JpZXMsIGNyZWF0ZQpmb2xkZXJzIGFuZCBmaWxlLCBkZWxldGUgdGhlbSwgZXRjLgoKV2hlcmUgYW0gSSA/CgpgYGB7ciBmaWZ0aH0KZ2V0d2QoKQpgYGAKCjxjZW50ZXI+IVtdKGZpbGVfMS5wbmcpPC9jZW50ZXI+CgpPciB1c2UgdGhlIGZ1bmN0aW9uIGRpci5jcmVhdGUoKToKCmBgYHtyIHNpeHRofQpkaXIuY3JlYXRlKCJ+L2ludHJvUi9pbnRyb19SIikKYGBgCgpZb3Ugc2hvdWxkIGNoYW5nZSB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5IHJpZ2h0IG5vdzoKCjxjZW50ZXI+IVtdKGZpbGVfMi5wbmcpPC9jZW50ZXI+CgpPciB1c2Ugc2V0d2QoKToKCmBgYHtyIHNldmVudGgsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnNldHdkKCJ+L2ludHJvUi9pbnRyb19SIikKYGBgCgo8Y2VudGVyPiFbXShmaWxlXzMucG5nKTwvY2VudGVyPgoKIyMjIFRoZSBzY3JpcHQgcGFuZSAoQykKClRoaXMgaXMgd2hlcmUgeW91IHdyaXRlIHlvdXIgUiBzY3JpcHRzLiBUaGlzIGFsc28gYWNjZXB0cyBvdGhlcgpsYW5ndWFnZXMgKGUuZy4gYmFzaCwgcHl0aG9uLCDigKYpLCBidXQgUiBTdHVkaW8gc2hpbmVzIGZvciBpdHMgUgppbnRlZ3JhdGlvbi4KCjxjZW50ZXI+IVtdKGV4YW1wbGVfc2NyaXB0cy5wbmcpPC9jZW50ZXI+CgpQbGVhc2UsIHBsZWFzZSAhIFdyaXRlIHlvdXIgY29tbWFuZHMgaW4gdGhlIFNjcmlwdCBwYW5lLCB0aGVuIGV4ZWN1dGUKdGhlbSBieSBoaXR0aW5nIENUUkwgKyBFbnRlci4gVGhpcyBpcyB2ZXJ5IG11Y2ggbGlrZSB5b3VyIGxhYi13b3JrYm9vazoKdGhlIGhpc3RvcnkgcGFuZSBvbmx5IGtlZXBzIGEgbGltaXRlZCBudW1iZXIgb2YgZnVuY3Rpb24gaW4gbWVtb3J5IHdoaWxlCnRoaXMgc2NyaXB0IGtlZXBzIHlvdXIgY29tbWFuZHMgaW4gYSBmaWxlIG9uIHlvdXIgZGlzay4gWW91IG1heSBzaGFyZQppdCwgZWRpdCBpdCwgY29tbWVudCBpdCwgZXRjLgoKVExEUiDigJMgVG9vIExvbmcgRGlkbuKAmXQgUmVhZAoKR3JhcGhpYyBpbnRlcmZhY2UgcHJlc2VudGF0aW9uIDoKCmBgYCAgICAgICAgIApXcml0ZSBjb21tYW5kIGxpbmVzIGluIFNjcmlwdCBwYW5lCkV4ZWN1dGUgY29tbWFuZCBsaW5lcyBieSBoaXR0aW5nIENUUkwgKyBFbnRlciBmcm9tIHNjcmlwdCBwYW5lIGV0IHNlZSB0aGVtIGluIHRoZSBjb25zb2xlLgpIYXZlIGEgbG9vayBhdCB0aGUgZW52aXJvbm1lbnQgYW5kIGhpc3RvcnkgaW4gY2FzZSBvbiB0aGUgdXBwZXIgcmlnaHQgcGFuZQpTZWFyY2ggZm9yIGhlbHAgaW4gdGhlIGxvd2VyIHJpZ2h0IHBhbmUuCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgUgoKIyMgU3BlYWtpbmcgUgoKIyMjIFZvY2FidWxhcnkKCkEgKip2YXJpYWJsZSoqIGlzIGEgY29udGFpbmVyIG9yIGEgY29udGVudCBuYW1lZC4gQSBjb250YWluZXIgaXMgYW4KKipvYmplY3QqKi4gQSBjb250ZW50IGlzIGFuIGVsZW1lbnQuIEluc2lkZSBlbGVtZW50cywgd2UgZGlzdGluZ3Vpc2gKYmV0d2VlbiAqKmRhdGEqKiBhbmQgKiptZXRhZGF0YSoqLiBXZSBtYW5pcHVsYXRlIGVsZW1lbnRzIGluc2lkZSBhbgpvYmplY3Qgd2l0aCAqKmZ1bmN0aW9ucyoqLgoKV2UgdGFsayBpbiBSIHdpdGggY29tbWFuZHMgdG8gZG8gYSB0YXNrIGluIGFwcGxpY2F0aW9uIG9mIHJ1bGVzIGFuZCBpbgpmb2xsb3dpbmcgYmVzdC1wcmFjdGljZSBndWlkZWxpbmVzLiBUaGUgcHJvY2VzcyBpcyBub3QgbGluZWFyIDogaXQgY2FuCmJlIG1vZGlmaWVkIGJ5IGRpZmZlcmVudCAqKmNvbnRyb2wgc3RydWN0dXJlcyoqLiBUaGUgd2hvbGUgZGVzY3JpYmVzIGFuCioqYWxnb3JpdGhtKiouCgpJbiB0aGUgZ29vZCBjb25kaXRpb25zLCB3ZSB1c2UgYSAid29yayBwbGFuZSIgYXMgYW4gKipJREUqKiBhcyBSc3R1ZGlvLgpPYmplY3QgaGF2ZSBwcm9wZXJ0aWVzIDogKip0eXBlcyoqLCAqKmRhdGEgc3RydWN0dXJlKiosICoqZGltZW5zaW9uKiosCioqY2xhc3MqKiwgKipmdW5jdGlvbnMqKgoKIyMjIFBhY2thZ2VzCgojIyMjIC4uLiBpbiBJRkIgY29yZSBjbHVzdGVyCgpZb3UgbWF5IGluc3RhbGwgYSBuZXcgcGFja2FnZSBvbiB5b3VyIGxvY2FsIGNvbXB1dGVyLiBZb3Ugc2hhbGwgbm90IGRvCml0IG9uIGEgY2x1c3Rlci4gVGhlIElGQiBjb3JlIGNsdXN0ZXIgeW91IGFyZSB3b3JraW5nIG9uIHRvZGF5IGlzIHNoYXJlZAphbmQgaGlnaGx5IHZhbHVhYmxlIDsgbm8gb25lIGNhbiBpbnN0YWxsIGFueXRoaW5nIGJlc2lkZXMgdGhlIG9mZmljaWFsCm1haW50YWluZXJzLgoKVGhlIGZvbGxvd2luZyBsaW5lcyBhcmUgd3JpdHRlbiBmb3IgaW5zdHJ1Y3Rpb24gcHVycG9zZSBhbmQgc2hvdWxkIG5vdApiZSB1c2VkIG9uIElGQiBjb3JlIGNsdXN0ZXIuCgojIyMjIC4uLiBpbiBsb2NhbAoKQSBwYWNrYWdlIGlzIGEgY29sbGVjdGlvbiBvZiBmdW5jdGlvbnMgb3JnYW5pemluZyB0byBtYWtlIGEgam9iIGluIGEKZmllbGQgV2UgY2FuIHNob3cgdGhlc2UgZnVuY3Rpb25zIGluIGNoZWF0LXNoZWV0cyBvciBpbiBhIHR1dG9yaWFsLiBcIyMjCkhvdyBjYWxsaW5nIHBhY2thZ2VzID8gVGhlcmUgYXJlIDIgbWV0aG9kcyB0byBjYWxsIGEgcGFja2FnZSA6CmBsaWJyYXJ5KClgIGFuZCBgcmVxdWlyZSgpYAoKYGxpYnJhcnlgIGxvYWQgaW4gZ2xvYmFsIGVudmlyb25tZW50IGFuZCBzdG9wIHByb2Nlc3MgaWYgcGFja2FnZSBkb24ndAppbnN0YWxsZWQgUGVyZmVjdCBhdCB0aGUgc3RhcnQgb2YgYSBzY3JpcHQKCmBgYHtyIG0xfQojbGlicmFyeShTZXVyYXQpCmBgYAoKYHJlcXVpcmVgIGxvYWQgaW4gZ2xvYmFsIGVudmlyb25tZW50IGFuZCByZXR1cm4gVFJVRS9GQUxTRSBpZiBwYWNrYWdlCmRvbid0IGluc3RhbGxlZCBQZXJmZWN0IGZvciBmdW5jdGlvbnMKCmBgYHtyIG0yfQojcmVxdWlyZShTZXVyYXQpCmBgYAoKIyMjIEhvdyBpbnN0YWxsaW5nIHBhY2thZ2VzID8KCllvdSBtYXkgaW5zdGFsbCBhIG5ldyBwYWNrYWdlIG9uIHlvdXIgbG9jYWwgY29tcHV0ZXIuIFlvdSBzaGFsbCBub3QgZG8KaXQgb24gYSBjbHVzdGVyLiBUaGUgSUZCIGNvcmUgY2x1c3RlciB5b3UgYXJlIHdvcmtpbmcgb24gdG9kYXkgaXMgc2hhcmVkCmFuZCBoaWdobHkgdmFsdWFibGUgOyBubyBvbmUgY2FuIGluc3RhbGwgYW55dGhpbmcgYmVzaWRlcyB0aGUgb2ZmaWNpYWwKbWFpbnRhaW5lcnMuCgpUaGUgZm9sbG93aW5nIGxpbmVzIGFyZSB3cml0dGVuIGZvciBpbnN0cnVjdGlvbiBwdXJwb3NlIGFuZCBzaG91bGQgbm90CmJlIHVzZWQgb24gSUZCIGNvcmUgY2x1c3Rlci4KCjxjZW50ZXI+IVtdKHBhY2thZ2VzLnBuZyk8L2NlbnRlcj4KClRoZXJlIGFyZSBkaWZmZXJlbnQgZnVuY3Rpb25zIHRvIGluc3RhbGwgYSBwYWNrYWdlIDoKCi0gICBjbGFzc2ljCgpgYGB7ciBtM30KI2luc3RhbGwucGFja2FnZXMoU2V1cmF0KQpgYGAKClRoaXMgd2lsbCByYWlzZSBhIHByb21wdCBhc2tpbmcgZm9yIHNpbXBsZSBxdWVzdGlvbnMgOiB3aGVyZSB0byBkb3dubG9hZApmcm9tIChjaG9vc2Ugc29tZXdoZXJlIGluIEZyYW5jZSksIHdoZXRoZXIgdG8gdXBkYXRlIG90aGVyIHBhY2thZ2VzIG9yCm5vdC4KCkRvIG5vdCBiZSBhZnJhaWQgYnkgdGhlIGxhcmdlIGFtb3VudCBvZiB0aGluZ3MgcHJvbXB0ZWQgaW4gdGhlIGNvbnNvbGUKYW5kIGxldCBSIGRvIHRoZSB0cmljay4KCkFsdGVybmF0aXZlbHksIHlvdSBjYW4gY2xpY2sgVG9vbCAtXD4gSW5zdGFsbCBQYWNrYWdlcyBpbiBSU3R1ZGlvLgoKWW91IGNhbiBsaXN0IGluc3RhbGxlZCBwYWNrYWdlcyB3aXRoIGluc3RhbGxlZC5wYWNrYWdlcygpLCBhbmQgZmluZCBmb3IKcGFja2FnZXMgdGhhdCBjYW4gYmUgdXBkYXRlcyB3aXRoIG9sZC5wYWNrYWdlcygpLiBUaGVzZSBwYWNrYWdlcyBjYW4gYmUKdXBkYXRlZCB3aXRoIHVwZGF0ZS5wYWNrYWdlcygpLgoKV2hpbGUgdGhlIGZ1bmN0aW9uIGluc3RhbGwucGFja2FnZXMoKSBzZWFyY2hlcyBwYWNrYWdlcyBpbiB0aGUgY29tbW9uIFIKcGFja2FnZSBsaXN0LCBtYW55IGJpb2luZm9ybWF0aWNzIHBhY2thZ2VzIGFyZSBhdmFpbGFibGUgb24gb3RoZXIgc2hhcmVkCnBhY2thZ2VzIHdhcmVob3VzZXMuIEp1c3QgbGlrZSBBcHBsZVN0b3JlIGFuZCBHb29nbGVTdG9yZSBkbyBub3QgaGF2ZQp0aGUgc2FtZSBhcHBsaWNhdGlvbnMgb24gbW9iaWxlLCBSIGhhcyBtdWx0aXBsZSBzb3VyY2VzIGZvciBpdHMKcGFja2FnZXMuIFlvdSBuZWVkIHRvIGtub3cgb25lIG9mIHRoZW0sIGFuZCBvbmUgb25seSBCaW9jb25kdWN0b3IuCgotICAgYmlvY29uZHVjdG9yCgpgYGB7ciBtNCwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQpCaW9jTWFuYWdlcjo6aW5zdGFsbChTZXVyYXQpCmBgYAoKLSAgIGRldnRvb2xzCgpgYGB7ciBtNSwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJkZXBvdF9naXRodWIiKQpkZXZ0b29sczo6aW5zdGFsbF9naXRsYWIoImRlcG90X2dpdGxhYiIpCmBgYAoKLSAgIHJlbW90ZXMKCmBgYHtyIG02LCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpyZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiZGVwb3RfZ2l0aHViIikKcmVtb3Rlczo6aW5zdGFsbF9naXRsYWIoImRlcG90X2dpdGxhYiIpCmBgYAoKVG9kYXksIGEgcGFja2FnZSBoYXMgZGVwZW5kZW5jaWVzIHRoYXQgYXJlIGFsc28gcGFja2FnZXMKCjxjZW50ZXI+IVtdKGRlcGVuZGVuY2VzLnBuZyk8L2NlbnRlcj4KCiMjIyBGZXcgdXNlZnVsbCBwYWNrYWdlcyBmb3IgZ2VuZXJhbCB1c2UKCjxjZW50ZXI+IVtdKHBhY2thZ2VzX3VzZWZ1bGwucG5nKTwvY2VudGVyPgoKIyMjIC4uLiBBbmQgaW4gc2luZ2xlIGNlbGwvbnVjbGVpL3NwYXRpYWwgdHJhbnNjcmlwdG9taWMKCjxjZW50ZXI+IVtdKG90aGVyX3VzZWZ1bGxfcGFja2FnZS5wbmcpPC9jZW50ZXI+CgojIyBUeXBlcwoKQXMgYW55IGxhbmd1YWdlLCB3ZSB1c2UgZGlmZmVyZW50IHN5bWJvbHMgdG8gZGlmZmVyZW50IGNvbmNlcHRzIDoKCi0gICBudW1iZXJzIChpbnRlZ2VyIGFuZCByZWFsKQotICAgY2hhcmFjdGVyCi0gICBib29sZWFuIChUUlVFIG9yIEZBTFNFKQotICAgZGF0ZQotICAgZmFjdG9yCgojIyMgTnVtYmVycwoKYGBge3IgYTF9CnZhbDEgPC0gMwpgYGAKCldpdGggdGhlIGNvZGUgYWJvdmUsIHRoZSBudW1iZXIgMyBpcyBzdG9yZWQgaW4gYSB2YXJpYWJsZSBjYWxsZWQg4oCcdmFsMeKAnS4KWW91IGNhbiBkbyB0aGlzIGluIFIgd2l0aCBhbnl0aGluZy4gTGl0ZXJhbGx5IGFueXRoaW5nLiBXaG9sZSBmaWxlcywKcGlwZWxpbmVzLCBpbWFnZXMsIGFueXRoaW5nLgoKTWF0aHMgaW4gUiB3b3JrcyB0aGUgc2FtZSBhcyB5b3VyIHJlZ3VsYXIgY2FsY3VsYXRvcjoKCmBgYHtyIGEyfQozICsgdmFsMSAjIEFkZApgYGAKCmBgYHtyIGEzfQozICsgdmFsMSAjIEFkZApgYGAKCmBgYHtyIGE0fQo0IC8gMiAjIERpdmlkZQpgYGAKCmBgYHtyIGE1fQozICogNCAjIE11bHRpcGx5CmBgYAoKYGBge3IgYTZ9CjcgJS8lIDIgIyBGbG9vciBkaXZpc2lvbgpgYGAKCiMjIyBDaGFyYWN0ZXJzCgpDaGFyYWN0ZXJzIGFyZSBkZWxpbWl0ZWQgd2l0aCBxdW90ZXMsIGVpdGhlciBkb3VibGUgYCJgIG9yIHNpbmdsZSBgJ2AgOgoKYGBge3IgYjF9CnZhbDIgPC0gIjQiCnZhbDUgPC0gJzUnCgojIFRoZSBleGFtcGxlIGJlbG93IGlzIGEgdmVyeSBnb29kIGV4YW1wbGUgb2YKIyBob3cgdG8gbmV2ZXIgZXZlciBuYW1lIGEgdmFyaWFibGUuCuOCtyA8LSAiaGFwcHkiCmBgYAoKTWF0aGVtYXRpY3MgZG9lcyBub3Qgd29yayB3aXRoIGNoYXJhY3RlcnMgYXQgYWxsIOKApiBUcnkgdGhlIGZvbGxvd2luZzoKCmBgYHtyIGIyLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoiNCIgKyAxCnZhbDIgKyAxCmBgYAoKWW91IGNhbiB0cnkgdG8gdHVybiBjaGFyYWN0ZXJzIGluIG51bWJlcnMgd2l0aCB0aGUgZnVuY3Rpb246IGFzLm51bWVyaWM6CgpgYGB7ciBiM30KYXMubnVtZXJpYygiNCIpICsgMQpgYGAKCmBgYHtyIGI0fQphcy5udW1lcmljKHZhbDIpICsgMQpgYGAKCkEgZnVuY3Rpb24gaXMgYSBSIGNvbW1hbmQgdGhhdCBpcyBmb2xsb3dlZCBieSBwYXJlbnRoZXNpcyBgKGAgYW5kIGApYC4KQmV0d2VlbiB0aGVzZSBwYXJlbnRoZXNpcywgd2UgZW50ZXIgYXJndW1lbnRzLiBVc2UgdGhlIGhlbHAgcGFuZSB0byBoYXZlCmluZm9ybWF0aW9uIGFib3V0IHRoZSBsaXN0IG9mIGFyZ3VtZW50cyBleHBlY3RlZCBhbmQvb3IgdW5kZXJzdG9vZCBieSBhCmdpdmVuIGZ1bmN0aW9uLgoKQXMgc2FpZCBwcmV2aW91c2x5LCB5b3UgY2FuIHN0b3JlIGFueSBvZiB0aGUgcHJldmlvdXNseSB0eXBlZCBjb21tYW5kcwppbiBhIHZhcmlhYmxlOgoKYGBge3IgYjV9CnZhbDQgPC0gYXMubnVtZXJpYygiNCIpICsgMQp2YWw1IDwtIDEgKyAoMC41ICogMikKcHJpbnQodmFsNSkKYGBgCgpQbGVhc2UhIFBsZWFzZSEgR2l2ZSB5b3VyIHZhcmlhYmxlIGEgbmFtZSB1bmRlcnN0YW5kYWJsZSBieSBodW1hbnMuIEkKZG9u4oCZdCB3YW50IHRvIHNlZSBhbnkgb2YgeW91IGNhbGxpbmcgdGhlaXIgdmFyaWFibGUgYGFgLCBgYmAsIGBteV92YXJgCgojIyMgQm9vbGVhbgoKQXNpZGUgZnJvbSBjaGFyYWN0ZXJzIGFuZCBudW1iZXJzLCB0aGVyZSBpcyBhbm90aGVyIHZlcnkgaW1wb3J0YW50IHR5cGUKaW4gUiAoYW5kIGNvbXB1dGVyIHNjaWVuY2UgaW4gZ2VuZXJhbCk6IGJvb2xlYW5zLiBUaGVyZSBhcmUgdHdvIGJvb2xlYW4KdmFsdWVzIDogVFJVRSBhbmQgRkFMU0UuCgpgYGB7ciBjMX0KMyA+IDQKYGBgCgpgYGB7ciBjMn0KMTAgPCAyCmBgYAoKYGBge3IgYzN9CjUgPCAxMApgYGAKCiMjIyBGYWN0b3IKCkZhY3RvciBhcmUgc2ltaWxhciBhcyB2ZWN0b3IgYnV0Li4uIGl0J3MgYSBjYXRlZ29yaWNhbCB2ZWN0b3IuCgpgYGB7ciBjNH0KZmFjdG9yX2VsZW1lbnQgPC0gZmFjdG9yKHggPSBjKCIxIiwiMiIsIjQiLCI0IiwiNSIsIjYiLCIyIiwiMyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiMSIsIjIiLCIzIiwiNCIsIjUiLCI2IikpCnByaW50KGZhY3Rvcl9lbGVtZW50KQpgYGAKCmBgYHtyIGM1fQp0YWJsZShmYWN0b3JfZWxlbWVudCkKYGBgCgojIyBEYXRhIFN0cnVjdHVyZQoKVG8gbWFuaXB1bGF0ZSBpbmZvcm1hdGlvbiwgd2UgY29uc2VydmUgZGF0YSBpbiBhIGdyb3VwIGFuZCBpdCBkZXBlbmQgb2YKdGhlIHR5cGUgb3IgYSBjb21iaW5hdGlvbiBvZiB0eXBlCgotICAgdmVjdG9yCi0gICBtYXRyaXgKLSAgIGFycmF5Ci0gICBsaXN0Ci0gICBkYXRhLmZyYW1lCgojIyMgVmVjdG9yCgpZb3UgY2FuIG1ha2UgdmVjdG9ycyBpbiBSLiBEb27igJl0IHBhbmljLCB0aGVyZSB3aWxsIGJlIG5vIG1hdGhzIGluIHRoaXMKcHJlc2VudGF0aW9uLgoKSW4gUiwgdmVjdG9ycyBhcmUgY3JlYXRlZCB3aXRoIHRoZSBmdW5jdGlvbiBgY2A6CgpgYGB7ciBlMX0KdmVjdG9yX251bWJlcnMgPC0gYygiMSIsICIyIiwgIjMiLCAiNCIsICIxMCIsICIyMCIpCnByaW50KHZlY3Rvcl9udW1iZXJzKQpgYGAKCmBgYHtyIGUyfQppcy52ZWN0b3IodmVjdG9yX251bWJlcnMpCmBgYAoKT25lIGNhbiBzZWxlY3QgYW4gZWxlbWVudCBvZiB0aGUgdmVjdG9yIHdpdGggc3F1YXJlZCBicmFja2V0cyBgW2AgYW5kCmBdYDoKCmBgYHtyIGUzfQp2ZWN0b3JfbnVtYmVyc1sxXQpgYGAKCk9uZSBjYW4gc2VsZWN0IG11bHRpcGxlIGVsZW1lbnRzIG9mIGEgdmVjdG9yIHdpdGggYDpgOgoKYGBge3IgZTR9CnZlY3Rvcl9udW1iZXJzWzI6NF0KYGBgCgpPayA/IFNvLCB2ZWN0b3IgaXMgc2ltcGx5IGRhdGEgaW4gb25lIGRpbWVuc2lvbiBcIyMjIyBRdWVzdGlvbnMKClF1ZXN0aW9uIDE6IElzIHRoZXJlIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZXNlIHR3byB2ZWN0b3JzID8KCmBgYHtyIGU1fQpjX3ZlY3RvciA8LSBjKCIxIiwgIjIiLCAiMyIsICIzIikKbl92ZWN0b3IgPC0gYyggMSwgICAyLCAgIDMsICAgMyApCmBgYAoKUXVlc3Rpb24gMjogQ2FuIEkgaW5jbHVkZSBib3RoIHRleHQgYW5kIG51bWJlcnMgaW4gYSB2ZWN0b3IgPwoKYGBge3IgZTZ9Cm1peGVkX3ZlY3RvciA8LSBjKDEsICIyIiwgMykKYGBgCgojIyMgTWF0cml4L0FycmF5CgpNYXRyaXggaXMgYSB0YWJsZSBpbiB0d28gZGltZW5zaW9ucyA6IHJvdyBhbmQgY29sdW1uCgpgYGB7ciBlN30KbWF0IDwtIG1hdHJpeCgxOjEyLCBucm93PTMsIG5jb2w9NCkKcHJpbnQobWF0KQpgYGAKClRvIGFjY2VzcyBpbiBvbmUgZWxlbWVudCB0byBjcm9zcyByb3cgYW5kIGNvbHVtbiA6CgpgYGB7ciBlOH0KbWF0WzIsM10KYGBgCgpBcnJheSBpcyBhIHRhYmxlIGluIDMgYW5kIG1vcmUgZGltZW5zaW9uLgoKQmFzaWNhbGx5LCBpbiAzRCwgeW91ciBoYXZlIGEgY3ViZSwgaW4gbkQsIHlvdXIgaGF2ZSBhIGh5cGVyY3ViZS4KClRoZSBhZHZhbnRhZ2Ugb2YgbWF0cmljZXMgYW5kIGFycmF5cyBpcyB0aGF0IHlvdSBjYW4gYXBwbHkKdHJhbnNmb3JtYXRpb25zIHRvIHRoZW0sIGJlY2F1c2UgdGhlc2UgZGF0YSBzdHJ1Y3R1cmVzIGFjY2VwdCBvbmx5IG9uZQp0eXBlLgoKYGBge3IgZTl9Cm1hdDIgPC0gbG9nKG1hdCkKcHJpbnQobWF0MikKYGBgCgojIyMgRGF0YS5mcmFtZQoKSW4gUiwgdGFibGVzIGFyZSBjcmVhdGVkIHdpdGggdGhlIGZ1bmN0aW9uIGRhdGEuZnJhbWU6CgpgYGB7ciBoMX0KZGF0YWZyYW1lX251bWJlcnMgPC0gZGF0YS5mcmFtZShjKDEsIDMpLCBjKDIsIDQpKQpwcmludChkYXRhZnJhbWVfbnVtYmVycykKYGBgCgpZb3UgY2FuIHJlbmFtZSBjb2x1bW5zIGFuZCByb3cgbmFtZXMgcmVzcGVjdGl2ZWx5IHdpdGggZnVuY3Rpb24KYGNvbG5hbWVzKClgIGFuZCBgcm93bmFtZXMoKWAuCgpgYGB7ciBoMn0KY29sbmFtZXMoZGF0YWZyYW1lX251bWJlcnMpIDwtIGMoIkNvbF8xXzMiLCAiQ29sXzJfNCIpCnJvd25hbWVzKGRhdGFmcmFtZV9udW1iZXJzKSA8LSBjKCJSb3dfMV8yIiwgIlJvd18zXzQiKQpwcmludChkYXRhZnJhbWVfbnVtYmVycykKYGBgCgpZb3UgY2FuIGFjY2VzcyBhIGNvbHVtbiBhbmQgYSBsaW5lIG9mIHRoZSBkYXRhIGZyYW1lIHVzaW5nIHNxdWFyZWQKYnJhY2tldHMgYFtgIGFuZCBgXWAuIFVzZSB0aGUgZm9sbG93aW5nIHN5bnRheDogYFtyb3csIGNvbHVtbl1gLiBVc2UKZWl0aGVyIHRoZSBuYW1lIG9mIHRoZSByb3cvY29sdW1uIG9yIGl0cyBwb3NpdGlvbi4KCmBgYHtyIGgzfQojIFNlbGVjdCBhIHJvdyBieSBpdHMgbmFtZQpwcmludChkYXRhZnJhbWVfbnVtYmVyc1siUm93XzFfMiIsIF0pCmBgYAoKYGBge3IgaDR9CiMgU2VsZWN0IGEgcm93IGJ5IGl0cyBpbmRleApwcmludChkYXRhZnJhbWVfbnVtYmVyc1sxLCBdKQpgYGAKCmBgYHtyIGg1fQogIyBTZWxlY3QgYSBjb2x1bW4gYnkgaXRzIG5hbWUKcHJpbnQoZGF0YWZyYW1lX251bWJlcnNbLCAiQ29sXzFfMyJdKQpgYGAKCmBgYHtyIGg2fQogIyBTZWxlY3QgYSBjb2x1bW4gYnkgaXRzIGluZGV4CnByaW50KGRhdGFmcmFtZV9udW1iZXJzWywgMV0pCmBgYAoKYGBge3IgaDd9CiAjIFNlbGVjdCBhIGNlbGwgaW4gdGhlIHRhYmxlCnByaW50KGRhdGFmcmFtZV9udW1iZXJzWyJSb3dfMV8yIiwgIkNvbF8xXzMiXSkKYGBgCgpgYGB7ciBoOH0KIyBTZWxlY3QgdGhlIGZpcnN0IHR3byByb3dzIGFuZCB0aGUgZmlyc3QgY29sdW1uIGluIHRoZSB0YWJsZQpwcmludChkYXRhZnJhbWVfbnVtYmVyc1sxOjIsIDFdKSAKYGBgCgpJZiB5b3UgbGlrZSBtYXRocywgeW91IHdpbGwgcmVtZW1iZXIgdGhlIG9yZGVyIGBbcm93LCBjb2x1bW5dYC4gSWYKeW914oCZcmUgbm90IGZhbWlsaWFyIHdpdGggdGhhdCwgdGhlbiB5b3Ugd2lsbCBkbyBsaWtlIDk5JSBvZiBhbGwgc29mdHdhcmUKZW5naW5lZXI6IHlvdSB3aWxsIHdyaXRlIGBbY29sdW1uLCByb3ddYCwgYW5kIHlvdSB3aWxsIGdldCBhbiBlcnJvci4KVHJ1c3QgbWUuIDk5JS4gUmVtZW1iZXIsIGFuIGVycm9yIGlzIG5ldmVyIGEgcHJvYmxlbSBpbiBpbmZvcm1hdGljcwoKIyMjIExpc3QKCkluIFIsIGxpc3QgaXMgYSBjb2xsZWN0aW9uIG9mIG90aGVycyBkYXRhIHN0cnVjdHVyZXMuCgojIyMgUXVlc3Rpb24KClF1ZXN0aW9uIDogV2hvIGlzIHdoYXQgPwoKPGNlbnRlcj4hW10oZGF0YXN0cnVjdHVyZS5wbmcpPC9jZW50ZXI+CgojIyMjIFJlYWQgYSB0YWJsZSBhcyBkYXRhIGZyYW1lCgpFeGVyY2lzZTogVXNlIHRoZSBIZWxwIHBhbmUgdG8gZmluZCBob3cgdG8gdXNlIHRoZSBmdW5jdGlvbiByZWFkLmNzdi4KWW91IGNhbiBmaW5kIGBleGFtcGxlX3RhYmxlLmNzdmAgaW4KYC9zaGFyZWQvcHJvamVjdHMvMjUzOF9lYjNpX24xXzIwMjUvYXRlbGllcl9zY3JuYXNlcS9URC9gCgpVc2UgdGhlIGZ1bmN0aW9uIHJlYWQuY3N2IHRvOgoKMS4gIGNvcHkgYW5kIG9wZW4gdGhlIGZpbGUgLi9leGFtcGxlX3RhYmxlLmNzdiBpbiB5b3VyIHByb2plY3QKICAgIGRpcmVjdG9yeS4KMi4gIHRoaXMgdGFibGUgaGFzIGEgaGVhZGVyIChUUlVFKS4KMy4gIHRoaXMgdGFibGUgaGFzIHJvdyBuYW1lcyBpbiB0aGUgY29sdW1uIGNhbGxlZCDigJxlbnNlbWJsX2dlbmVfaWTigJ0uCgpMZXQgYWxsIG90aGVyIHBhcmFtZXRlcnMgdG8gdGhlaXIgZGVmYXVsdCB2YWx1ZXMuCgpTYXZlIHRoZSBvcGVuZWQgdGFibGUgaW4gYSB2YXJpYWJsZSBjYWxsZWQgZXhhbXBsZV90YWJsZS4KCk5vdyBsZXQgdXMgZXhwbG9yZSB0aGlzIGRhdGFzZXQuCgpXZSBjYW4gY2xpY2sgb24gZW52aXJvbm1lbnQgcGFuZSA6CgpCZSBjYXJlZnVsLCBsYXJnZSB0YWJsZSBtYXkgaGFuZyB5b3VyIHNlc3Npb24uCgpBbHRlcm5hdGl2ZWx5LCB3ZSBjYW4gdXNlIHRoZSBmdW5jdGlvbiBgaGVhZGAgd2hpY2ggcHJpbnRzIHRoZSBmaXJzdApsaW5lcyBvZiBhIHRhYmxlOgoKYGBge3IgaDl9CmV4YW1wbGVfdGFibGUgPC0gcmVhZC5jc3YoImV4YW1wbGVfdGFibGUuY3N2IikKaGVhZChleGFtcGxlX3RhYmxlKQpgYGAKCmBgYHtyIGg5YmlzfQpsaWJyYXJ5KHJlYWR4bCkKZXhhbXBsZV90YWJsZSA8LSByZWFkX3hsc3goImV4YW1wbGVfdGFibGUueGxzeCIpCmhlYWQoZXhhbXBsZV90YWJsZSkKYGBgCgpUaGUgZnVuY3Rpb24gc3VtbWFyeSBkZXNjcmliZXMgdGhlIGRhdGFzZXQgcGVyIHNhbXBsZToKCmBgYHtyIGgxMH0Kc3VtbWFyeShleGFtcGxlX3RhYmxlKQpgYGAKCkhhdmUgYSBsb29rIGF0IHRoZSBzdW1tYXJ5IG9mIHRoZSBkYXRhc2V0IHBlciBnZW5lLCB1c2luZyB0aGUgZnVuY3Rpb24gdAp0byB0cmFuc3Bvc2U6CgpgYGB7ciBoMTF9CmhlYWQodChleGFtcGxlX3RhYmxlKSkKYGBgCgpgYGB7ciBoMTJ9CnN1bW1hcnkodChleGFtcGxlX3RhYmxlKSkKYGBgCgojIyBPYmplY3QKCkluIFIsIGV2ZXJ5dGhpbmcgaXMgYW4gb2JqZWN0ICEKCkFuIG9iamVjdCBpcyBhIGNvbnRhaW5lciB0aGF0IGhhcyBhIGRlZmluZWQgY2xhc3Mgb2Ygb2JqZWN0cyBoYXZpbmcKcHJvcGVydGllcywgc3VjaCBhcyBkaW1lbnNpb25zIG9yIGEgZGF0YSBzdHJ1Y3R1cmUsIGFuZCBjb250YWlucwplbGVtZW50cyBoYXZpbmcgYSB0eXBlIGFuZCBhIHZhbHVlLgoKIyMgRnVuY3Rpb25zCgpGdW5jdGlvbnMgYXJlIHNjcmlwdCBibG9ja3MgY3JlYXRlZCB0byBwZXJmb3JtIHNwZWNpZmljIHRhc2tzLgoKV2UgYWxyZWFkeSBzZWUgZGlmZmVyZW50IGZ1bmN0aW9ucyA6CgpgYXMubnVtZXJpYygpYCAtIGBwcmludCgpYCAtIGBpcy52ZWN0b3IoKWAgLSBgZGF0YS5mcmFtZSgpYCAtIGBoZWFkKClgIC0KYHN1bW1hcnkoKWAgLSBgdCgpYAoKVGhlcmUgYXJlIGdlbmVyaWMgZnVuY3Rpb25zIHRvIHNwZWNpZmljIGNsYXNzCgpgYGB7ciBqMn0KI2dldFMzbWV0aG9kKCJwcmludCIsICJkYXRhLmZyYW1lIikKcHJpbnQuZGF0YS5mcmFtZSA9IGZ1bmN0aW9uICh4LCAuLi4sIGRpZ2l0cyA9IE5VTEwsIHF1b3RlID0gRkFMU0UsIHJpZ2h0ID0gVFJVRSwgCiAgICByb3cubmFtZXMgPSBUUlVFLCBtYXggPSBOVUxMKSAKewogICAgbiA8LSBsZW5ndGgocm93Lm5hbWVzKHgpKQogICAgaWYgKGxlbmd0aCh4KSA9PSAwTCkgewogICAgICAgIGNhdChzcHJpbnRmKG5nZXR0ZXh0KG4sICJkYXRhIGZyYW1lIHdpdGggMCBjb2x1bW5zIGFuZCAlZCByb3ciLCAKICAgICAgICAgICAgImRhdGEgZnJhbWUgd2l0aCAwIGNvbHVtbnMgYW5kICVkIHJvd3MiKSwgbiksICJcbiIsIAogICAgICAgICAgICBzZXAgPSAiIikKICAgIH0KICAgIGVsc2UgaWYgKG4gPT0gMEwpIHsKICAgICAgICBwcmludC5kZWZhdWx0KG5hbWVzKHgpLCBxdW90ZSA9IEZBTFNFKQogICAgICAgIGNhdChnZXR0ZXh0KCI8MCByb3dzPiAob3IgMC1sZW5ndGggcm93Lm5hbWVzKVxuIikpCiAgICB9CiAgICBlbHNlIHsKICAgICAgICBpZiAoaXMubnVsbChtYXgpKSAKICAgICAgICAgICAgbWF4IDwtIGdldE9wdGlvbigibWF4LnByaW50IiwgOTk5OTlMKQogICAgICAgIGlmICghaXMuZmluaXRlKG1heCkpIAogICAgICAgICAgICBzdG9wKCJpbnZhbGlkICdtYXgnIC8gZ2V0T3B0aW9uKFwibWF4LnByaW50XCIpOiAiLCAKICAgICAgICAgICAgICAgIG1heCkKICAgICAgICBvbWl0IDwtIChuMCA8LSBtYXglLyVsZW5ndGgoeCkpIDwgbgogICAgICAgIG0gPC0gYXMubWF0cml4KGZvcm1hdC5kYXRhLmZyYW1lKGlmIChvbWl0KSAKICAgICAgICAgICAgeFtzZXFfbGVuKG4wKSwgLCBkcm9wID0gRkFMU0VdCiAgICAgICAgZWxzZSB4LCBkaWdpdHMgPSBkaWdpdHMsIG5hLmVuY29kZSA9IEZBTFNFKSkKICAgICAgICBpZiAoIWlzVFJVRShyb3cubmFtZXMpKSAKICAgICAgICAgICAgZGltbmFtZXMobSlbWzFMXV0gPC0gaWYgKGlzRkFMU0Uocm93Lm5hbWVzKSkgCiAgICAgICAgICAgICAgICByZXAuaW50KCIiLCBpZiAob21pdCkgCiAgICAgICAgICAgICAgICAgIG4wCiAgICAgICAgICAgICAgICBlbHNlIG4pCiAgICAgICAgICAgIGVsc2Ugcm93Lm5hbWVzCiAgICAgICAgcHJpbnQobSwgLi4uLCBxdW90ZSA9IHF1b3RlLCByaWdodCA9IHJpZ2h0LCBtYXggPSBtYXgpCiAgICAgICAgaWYgKG9taXQpIAogICAgICAgICAgICBjYXQoIiBbIHJlYWNoZWQgJ21heCcgLyBnZXRPcHRpb24oXCJtYXgucHJpbnRcIikgLS0gb21pdHRlZCIsIAogICAgICAgICAgICAgICAgbiAtIG4wLCAicm93cyBdXG4iKQogICAgfQogICAgaW52aXNpYmxlKHgpCn0KYGBgCgpXZSBjb3VsZCBiZSBjcmVhdGUgbmV3IGZ1bmN0aW9ucwoKYGBge3IgajN9CgpjYWxjdWxhdGVfdG90byA8LSBmdW5jdGlvbih4LHkpIHsKICAKICBpZiAoeCA9PSAwICYgeSA9PSB4KSB7CiAgICByZXR1cm4oInRldGUgYSB0b3RvICEiKQogIH0gZWxzZSB7CiAgICByZXR1cm4oeCArIHkpCiAgfQp9CgpjYWxjdWxhdGVfdG90byh4PTAseT0wKQpjYWxjdWxhdGVfdG90byh4PTEseT0wKQpjYWxjdWxhdGVfdG90byh4PTAseT0xKQpjYWxjdWxhdGVfdG90byh4PTEseT0xKQpgYGAKClIgaXMgeW91ciBiZXN0IGZyaWVuZCBidXQuLi5zb21ldGltZXMsIGl0IHdhbnQgeW91ciBnYWluIHRpbWUgYW5kCmFyZ3VtZW50cyBhcmUgImluZGV4aW5nIiB3aGVuIHlvdSBjYWxsZWQgZnVuY3Rpb24uICoqQlVUIElUIElTIE5PVApSRUNPTU1BTkRFRCoqCgpgYGB7ciBqNH0KY2FsY3VsYXRlX3RvdG8oMCwwKQpgYGAKCjxjZW50ZXI+IVtdKGFueV9mdW5jdGlvbnNfc2V1cmF0LnBuZyk8L2NlbnRlcj4KCiMjIENvbnRyb2wgU3RydWN0dXJlcwoKQSBzY3JpcHQgaXMganVzdCBhbiBleGVjdXRpb24gZmxvdy4KCldlIGNvdWxkIGJlIG1vZGlmeSB0aGlzIGZsb3cgd2l0aCA6CgotICAgY29uZGl0aW9uYWwgc3RydWN0dXJlcwoKLSAgIGxvb3AKCi0gICBpbnRlcm4gZmx1eCBzdHJ1Y3R1cmVzCgo8Y2VudGVyPiFbXShjb250cm9sX3N0cnVjdHVyZS5wbmcpPC9jZW50ZXI+CgojIyBTcGVjaWFsIGZ1bmN0aW9ucwoKTWFueSBmdW5jdGlvbnMgYXJlIGJ1aWx0IHRvIHBlcmZvcm0gc3BlY2lmaWMgYW5kIG9wdGltaXplZCB0YXNrcwoKLSAgIFZlY3RvcmlzZSBmdW5jdGlvbnMKCmBgYHtyIGwxfQpzY29yZXMgPC0gYygxMiwgOCwgMTUsIDcsIDIwKQoKcmVzdWx0cyA8LSBpZmVsc2Uoc2NvcmVzID49IDEwLCAiUGFzcyIsICJGYWlsIikKCnByaW50KHJlc3VsdHMpCgpzY29yZSA8LSAxNQppZiAoc2NvcmUgPj0gMTApIHsKICBwcmludCgiUGFzcyIpCn0gZWxzZSB7CiAgcHJpbnQoIkZhaWwiKQp9CgpgYGAKCi0gICBJdGVyYXRpdmUgYXBwbGljYXRpdmUgZnVuY3Rpb25zCgpgYGB7ciBsNX0KbXlfbGlzdCA8LSBsaXN0KGEgPSAxOjUsIGIgPSA2OjEwLCBjID0gMTE6MTUpCnJlc3VsdF9sYXBwbHkgPC0gbGFwcGx5KG15X2xpc3QsIG1lYW4pCnByaW50KHJlc3VsdF9sYXBwbHkpCmBgYAoKYGBge3IgbDZ9CnJlc3VsdF9zYXBwbHkgPC0gc2FwcGx5KG15X2xpc3QsIG1lYW4pCnByaW50KHJlc3VsdF9zYXBwbHkpCmBgYAoKYGBge3IgbDh9Cm1hdCA8LSBtYXRyaXgoMTo5LCBucm93ID0gMywgYnlyb3cgPSBUUlVFKQpwcmludChtYXQpCnJvd19tZWFucyA8LSBhcHBseShtYXQsIDEsIG1lYW4pCnByaW50KHJvd19tZWFucykKY29sX21lYW5zIDwtIGFwcGx5KG1hdCwgMiwgbWVhbikKcHJpbnQoY29sX21lYW5zKQpgYGAKCi0gICBGdW5jdGlvbmFsIGZ1bmN0aW9ucwoKYGBge3IgbDEwfQpudW1iZXJzIDwtIDE6MTAKCiMgR2FyZGVyIHNldWxlbWVudCBsZXMgbm9tYnJlcyBwYWlycwpldmVuX251bWJlcnMgPC0gRmlsdGVyKGZ1bmN0aW9uKHgpIHggJSUgMiA9PSAwLCBudW1iZXJzKQoKcHJpbnQoZXZlbl9udW1iZXJzKQoKYGBgCgpgYGB7ciBsMTF9Cmxpc3QxIDwtIGxpc3QoMSwgMiwgMykKbGlzdDIgPC0gbGlzdCgxMCwgMjAsIDMwKQoKIyBBam91dGVyIGxlcyDDqWzDqW1lbnRzIGNvcnJlc3BvbmRhbnRzCnJlc3VsdCA8LSBNYXAoZnVuY3Rpb24oeCwgeSkgeCArIHksIGxpc3QxLCBsaXN0MikKCnByaW50KHJlc3VsdCkKYGBgCgojIyBTYXZlcwoKUnN0dWRpbyBhcmUgdHdvIGZvcm1hdHMgOiBgLnJkc2AgYW5kIGAuUmRhdGFgCgojIyMgU2F2ZQoKV2hpbGUgd29ya2luZyBvbiB5b3VyIHByb2plY3RzIGFuZCBsZWFuaW5nIHRoaXMgd2VlaywgeW91IHdpbGwgcHJvY2VzcwpkYXRhc2V0cyBpbiBSLiBUaGUgcmVzdWx0cyBvZiB0aGVzZSBhbmFseXNlcyB3aWxsIGJlIHN0b3JlZCBvbgp2YXJpYWJsZXMuIFRoaXMgbWVhbnMsIHRoYXQgd2hlbiB5b3UgY2xvc2UgUlN0dWRpbywgc29tZSBvZiB0aGlzIHdvcmsKbWlnaHQgYmUgbG9zdC4KCldlIGFscmVhZHkgc2F3IHRoZSBmdW5jdGlvbiBgc2F2ZS5pbWFnZSgpYCB0byBzYXZlIGEgY29tcGxldGUgY29weSBvZgp5b3VyIHdvcmtpbmcgZW52aXJvbm1lbnQuCgpIb3dldmVyLCB5b3UgY2FuIHNhdmUgb25seSB0aGUgY29udGVudCBvZiBhIGdpdmUgdmFyaWFibGUuIFRoaXMgaXMKdXNlZnVsIHdoZW4geW91IHdhbnQgdG8gc2F2ZSB0aGUgcmVzdWx0IG9mIGEgZnVuY3Rpb24gKG9yIGEgcGlwZWxpbmUpCmJ1dCBub3QgdGhlIHdob2xlIDUgaG91cnMgb2Ygd29yayB5b3XigJl2ZSBiZWVuIHNwZW5kaW5nIG9uCmhvdy10by1tYWtlLXRoYXQtcGlwZWxpbmUtd29yay1jb3JyZWN0bHkuCgpUaGUgZm9ybWF0IGlzIGNhbGxlZDogUkRTIGZvciBSIERhdGEgU2VyaWFsaXphdGlvbi4gVGhpcyBpcyBkb25lIHdpdGgKdGhlIGZ1bmN0aW9uIGBzYXZlUkRTKClgOgoKYGBge3IgbjF9CnNhdmVSRFMob2JqZWN0ID0gZXhhbXBsZV90YWJsZSwgZmlsZSA9ICJleGFtcGxlX3RhYmxlLlJEUyIpCmBgYAoKIyMjIExvYWQKCllvdSBjYW4gYWxzbyBsb2FkIGEgUkRTIGludG8gYSB2YXJpYWJsZS4gVGhpcyBpcyB1c2VmdWwgd2hlbiB5b3UgcmVjZWl2ZQphIFJEUyBmcm9tIGEgY293b3JrZXIsIG9yIHlvdeKAmWQgbGlrZSB0byBrZWVwIGdvaW5nIHlvdXIgd29yayBmcm9tIGEKc2F2ZWQgcG9pbnQuIFRoaXMgaXMgZG9uZSB3aXRoIHRoZSBmdW5jdGlvbiBgcmVhZFJEUygpYDoKCmBgYHtyIG4yfQpleGFtcGxlX3RhYmxlIDwtIHJlYWRSRFMoZmlsZSA9ICJleGFtcGxlX3RhYmxlLlJEUyIpCmhlYWQoZXhhbXBsZV90YWJsZSkKYGBgCgpCdXQgdGhlcmUgYXJlIG90aGVyIHNvbHV0aW9ucyA6CgotICAgYGZzdGAsIGBxc2AsIGBmZWF0aGVyYCwgYHBhcnF1ZXRgCi0gICBgY3N2YCwgYHRzdmAsIGB4bHN4YCwgYHlhbWxgLCBganNvbmAKLSAgIGBTUUxpdGVgLCBgRHVja0RCYCwgYEhERjVgLCBgTW9uZXREQiBMaXRlYCwKICAgIGBGZWF0aGVyIElQQy9BcnJvdyBJUEMgc3RyZWFtc2AsCi0gICBgZ3pgLCBgYnoyYCwgYHh6YCwgYHppcGAKLSAgIGBiaW5haXJlYAoKIyMgSGVscAoKRGlyZWN0bHkgaW4gdGhlIHBhY2thZ2UgZG9jdW1lbnRhdGlvbiBpbiBIZWxwIHBhbmUgb3IgOgoKYGBge3IgeX0KP3ByaW50Cj8/cHJpbnQKYGBgCgo8Y2VudGVyPiFbXShoZWxwLnBuZyk8L2NlbnRlcj4KCiMjIFdyaXRpbmcgY29kZSBpbiBSc3R1ZGlvCgpPaywgaXQncyB0aW1lIHRvIHdyaXRlIFIgY29kZS4gQnV0IGhvdyBkbyB5b3UgZG8gdGhhdCA/IExpa2UgYSB3cml0aW5nIGEKYm9vayAhCgpCZXN0IHByYWN0aXNlcyA6CgotICAgPGh0dHBzOi8vc3R5bGUudGlkeXZlcnNlLm9yZy9zeW50YXguaHRtbD4KLSAgIENvbW1lbnQKLSAgIFNjcmlwdCBzdHJ1Y3R1cmUKCmBgYHtyIHp9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBTY3JpcHQgbmFtZSA6IGFuYWx5c2lzX3BpcGVsaW5lLlIKIyBBdXRob3IgICAgICA6IFlvdXIgTmFtZQojIERhdGUgICAgICAgIDogMjAyNS0xMS0xNQojIFB1cnBvc2UgICAgIDogRXhhbXBsZSBvZiBjbGVhbiBSIHNjcmlwdCBzdHJ1Y3R1cmUKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgMC4gTG9hZCBwYWNrYWdlcyAtLS0tCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyAxLiBEZWZpbmUgcGFyYW1ldGVycyAtLS0tCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyAyLiBEZWZpbmUgY3VzdG9tIGZ1bmN0aW9ucyAtLS0tCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyAzLiBMb2FkIGRhdGEgLS0tLQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgNC4gRGF0YSBjbGVhbmluZyAtLS0tCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyA1LiBBbmFseXNpcyAtLS0tCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyA2LiBWaXN1YWxpemF0aW9ucyAtLS0tCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyA3LiBTYXZlIG91dHB1dHMgLS0tLQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0K