Class 1

Data import and view

In order to see all the code click on Code in upper right and choose “Show all code”.

getwd() - This command return the current working directory of R session. all files read, save etc will happen in that directory by default.

setwd("path/to/the/right/directory") - Change (set) working directory. Windows users should use backslash/ to seperate directories and not normal slash (\) as default in windows.

read.csv("filename.csv") - read CSV (Comma Seperated Values) file. File name should be between qutotaion mark. by default it take the first line as header (or names) to the columns.

View(variable name) - Command that show nicely the variable in RStudio dedicated window.

vector[5] - return the 5 th element in a vector.

data.table[1,] - Return the first row and all columns from a a table.

data.table[,1] - Return the first columns and all rows from a a table.

names(variable) - Return the names (or columns) of the table.

Data

Data file: Iris1A.csv


getwd()

file1 = read.csv("Iris1A.csv")
pl8reader = file1
# View(pl8reader)

pl8reader[1,]
pl8reader[,1]
 
names(pl8reader)[1]

Plot with plotly

Install packages - you can use command install.packages("package-name"). Or you can use package tab (lower right pane) and clock install.

To use the package (or library) you can click on square near package name in the right window. Or better use the command library(package-name).

plotly gReat cheatsheet

# install.packages("plotly")
library(plotly)

plot_ly( data = pl8reader
        ,x = pl8reader$Time..s.
        ,y = pl8reader[,3]
        ) 
plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
        ,x = pl8reader$Time..s.
        ,y = pl8reader[,3]
        ) 

Google: plotly add line to plot plotly add name to legend

add_trace() - Command to add new trace to a graph. more information in the documentation page.

Another way to get the documentation is type in the console ?function-name anc click enter. or ??package-name for package help.

p = plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
        ,x = pl8reader$Time..s.
        ,y = pl8reader[,3]
        ,name = colnames(pl8reader)[3]
        ) 
add_trace(p
          ,y = pl8reader[,4]
          ,name = colnames(pl8reader)[4]
          )

layout() - documentation page Google: plotly r add main title

In order to show correct time in hours I just duvude the seconds value with 60*60=3600.


p = plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
        ,x = pl8reader$Time..s. /3600
        ,y = pl8reader[,3]
        ,name = colnames(pl8reader)[3]
        ) 
p = add_trace(p
          ,y = pl8reader[,4]
          ,name = colnames(pl8reader)[4]
          )
layout(p
       ,title = "Growth curve"
       ,yaxis = list(title = "OD<sub>600</sub> nm")
       ,xaxis = list(title = "Time (H)")
       )

Class 2

Error bars

Google: plotly r error bars

p = plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
        ,x = pl8reader$Time..s./3600
        ,y = pl8reader[,3]
        ,name = colnames(pl8reader)[3]
        ,error_y = ~list(value = pl8reader[,5])
        
        ) 
p = add_trace(p
          ,y = pl8reader[,4]
          ,name = colnames(pl8reader)[4]
          ,error_y = ~list(value = pl8reader[,6])
          )
layout(p
       ,title = "Growth curve"
       ,yaxis = list(title = "OD<sub>600</sub> nm")
       ,xaxis = list(title = "Time (H)")
       )

Error area

Google: plotly r area

upper_errorB4 = pl8reader[,3] + pl8reader[,5]
lower_errorB4 = pl8reader[,3] - pl8reader[,5]
upper_errorCa = pl8reader[,4] + pl8reader[,6]
lower_errorCa = pl8reader[,4] - pl8reader[,6]

p = plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
        ,x = pl8reader$Time..s./3600
        ,y = pl8reader[,3]
        ,name = colnames(pl8reader)[3]
)
p = add_trace(p, y = lower_errorB4)
p = add_trace(p, y = upper_errorB4, fill = "tonexty")

p = add_trace(p, y = pl8reader[,4], name = colnames(pl8reader)[4])
p = add_trace(p, y = lower_errorCa)
p = add_trace(p, y = upper_errorCa, fill = "tonexty")

layout(p
       ,title = "Growth curve"
       ,yaxis = list(title = "OD<sub>600</sub> nm")
       ,xaxis = list(title = "Time (H)")
       )
edge = list(color = 'rgba(0,0,0,0)')

p = plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
        ,x = pl8reader$Time..s./3600
        ,y = pl8reader[,3]
        ,name = colnames(pl8reader)[3]
)
p = add_trace(p, y = lower_errorB4, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorB4, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')

p = add_trace(p, y = pl8reader[,4],name = colnames(pl8reader)[4])
p = add_trace(p, y = lower_errorCa, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorCa, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')

layout(p
       ,title = "Growth curve"
       ,yaxis = list(title = "OD<sub>600</sub> nm")
       ,xaxis = list(title = "Time (H)")
       )

No grid no zeroline.

p = plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
        ,x = pl8reader$Time..s./3600
        ,y = pl8reader[,3]
        ,name = colnames(pl8reader)[3]
)
p = add_trace(p, y = lower_errorB4, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorB4, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')

p = add_trace(p, y = pl8reader[,4],name = colnames(pl8reader)[4])
p = add_trace(p, y = lower_errorCa, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorCa, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')

layout(p
       ,title = "Growth curve"
       ,yaxis = list(title = "OD<sub>600</sub> nm", showgrid = FALSE)
       ,xaxis = list(title = "Time (H)", showgrid = FALSE, zeroline = F)
       )

Loops

View(pl8reader)
seq(from = 1, to = 35, by = 2.3)
for(i in seq(from = 3, to = 29, by = 4))
{print(names(pl8reader)[i])}
p = plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
)

for(i in seq(from = 3, to = 29, by = 4)){
j=i+1
upper_errorB4 = pl8reader[,i] + pl8reader[,i+2]
lower_errorB4 = pl8reader[,i] - pl8reader[,i+2]
lower_errorB4[lower_errorB4<0] = 0
upper_errorCa = pl8reader[,j] + pl8reader[,j+2]
lower_errorCa = pl8reader[,j] - pl8reader[,j+2]
lower_errorCa[lower_errorCa<0] = 0


p = add_trace(p, y = pl8reader[,i], name = colnames(pl8reader)[i], color = bbb[i])
p = add_trace(p, y = lower_errorB4, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorB4, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')

p = add_trace(p, y = pl8reader[,j],name = colnames(pl8reader)[j], color = bbb[i])
p = add_trace(p, y = lower_errorCa, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorCa, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')
}

layout(p
       ,title = "Growth curve"
       ,yaxis = list(title = "OD<sub>600</sub> nm", showgrid = FALSE)
       ,xaxis = list(title = "Time (H)", showgrid = FALSE, zeroline = F))

Data file: Iris2A.csv


file2 = read.csv("Iris2A.csv")
pl8reader = file2

dim(pl8reader)

p = plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
)

for(i in seq(from = 2, to = 25, by = 4)){
j=i+1
upper_errorB4 = pl8reader[,i] + pl8reader[,i+2]
lower_errorB4 = pl8reader[,i] - pl8reader[,i+2]
lower_errorB4[lower_errorB4<0] = 0
upper_errorCa = pl8reader[,j] + pl8reader[,j+2]
lower_errorCa = pl8reader[,j] - pl8reader[,j+2]
lower_errorCa[lower_errorCa<0] = 0


p = add_trace(p, y = pl8reader[,i],name = colnames(pl8reader)[i])
p = add_trace(p, y = lower_errorB4, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorB4, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')

p = add_trace(p, y = pl8reader[,j],name = colnames(pl8reader)[j])
p = add_trace(p, y = lower_errorCa, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorCa, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')
}

layout(p
       ,title = "Growth curve"
       ,yaxis = list(title = "OD<sub>600</sub> nm", showgrid = FALSE)
       ,xaxis = list(title = "Time (H)", showgrid = FALSE, zeroline = F))

Data file: Iris3A.csv

Google: r read csv skip empty lines There is some problem about std


# file3 = read.csv("Iris3A.csv")
# file3 = read.csv(file = "Iris3A.csv" ,skip = as.numeric(rownames(file3[which(file3[,1]!=''),])[1]))
# pl8reader = file3[3:length(file3),]
# 
# View(pl8reader)

p = plot_ly( data = pl8reader
        ,type = "scatter"
        ,mode = "lines"
)

for(i in seq(from = 2, to = 29, by = 4)){
j=i+1
upper_errorB4 = pl8reader[,i] + pl8reader[,i+2]
lower_errorB4 = pl8reader[,i] - pl8reader[,i+2]
lower_errorB4[lower_errorB4<0] = 0
upper_errorCa = pl8reader[,j] + pl8reader[,j+2]
lower_errorCa = pl8reader[,j] - pl8reader[,j+2]
lower_errorCa[lower_errorCa<0] = 0


p = add_trace(p, y = pl8reader[,i],name = colnames(pl8reader)[i])
p = add_trace(p, y = lower_errorB4, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorB4, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')

p = add_trace(p, y = pl8reader[,j],name = colnames(pl8reader)[j])
p = add_trace(p, y = lower_errorCa, showlegend = F, line = edge)
p = add_trace(p, y = upper_errorCa, fill = "tonexty",showlegend = F, line = edge, fillcolor = 'rgba(1,1,1,0.1)')
}

layout(p
       ,title = "Growth curve"
       ,yaxis = list(title = "OD<sub>600</sub> nm", showgrid = FALSE)
       ,xaxis = list(title = "Time (H)", showgrid = FALSE, zeroline = F))
LS0tCnRpdGxlOiAiUGxvdGx5IHdvcmtzaG9wIgphdXRob3I6ICJSb3RlbSBIYWRhciIKZGF0ZTogIjR0aCBUYW11eiIKb3V0cHV0OiBodG1sX25vdGVib29rCgotLS0KIyBDbGFzcyAxCiMjIERhdGEgaW1wb3J0IGFuZCB2aWV3CgpJbiBvcmRlciB0byBzZWUgYWxsIHRoZSBjb2RlIGNsaWNrIG9uIGBDb2RlYCBpbiB1cHBlciByaWdodCBhbmQgY2hvb3NlICJTaG93IGFsbCBjb2RlIi4KCmBnZXR3ZCgpYCAtIFRoaXMgY29tbWFuZCByZXR1cm4gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnkgb2YgUiBzZXNzaW9uLiBhbGwgZmlsZXMgcmVhZCwgc2F2ZSBldGMgd2lsbCBoYXBwZW4gaW4gdGhhdCBkaXJlY3RvcnkgYnkgZGVmYXVsdC4KCmBzZXR3ZCgicGF0aC90by90aGUvcmlnaHQvZGlyZWN0b3J5IilgIC0gQ2hhbmdlIChzZXQpIHdvcmtpbmcgZGlyZWN0b3J5LiBXaW5kb3dzIHVzZXJzIHNob3VsZCB1c2UgYmFja3NsYXNoYC9gIHRvIHNlcGVyYXRlIGRpcmVjdG9yaWVzIGFuZCBub3Qgbm9ybWFsIHNsYXNoIChgXGApIGFzIGRlZmF1bHQgaW4gd2luZG93cy4KCmByZWFkLmNzdigiZmlsZW5hbWUuY3N2IilgIC0gcmVhZCBDU1YgKENvbW1hIFNlcGVyYXRlZCBWYWx1ZXMpIGZpbGUuIEZpbGUgbmFtZSBzaG91bGQgYmUgYmV0d2VlbiBxdXRvdGFpb24gbWFyay4gYnkgZGVmYXVsdCBpdCB0YWtlIHRoZSBmaXJzdCBsaW5lIGFzIGhlYWRlciAob3IgbmFtZXMpIHRvIHRoZSBjb2x1bW5zLgoKYFZpZXcodmFyaWFibGUgbmFtZSlgIC0gQ29tbWFuZCB0aGF0IHNob3cgbmljZWx5IHRoZSB2YXJpYWJsZSBpbiBSU3R1ZGlvIGRlZGljYXRlZCB3aW5kb3cuIAoKYHZlY3Rvcls1XWAgLSByZXR1cm4gdGhlIDUgdGggZWxlbWVudCBpbiBhIHZlY3Rvci4KCmBkYXRhLnRhYmxlWzEsXWAgLSBSZXR1cm4gdGhlIGZpcnN0IHJvdyBhbmQgYWxsIGNvbHVtbnMgZnJvbSBhIGEgdGFibGUuCgpgZGF0YS50YWJsZVssMV1gIC0gUmV0dXJuIHRoZSBmaXJzdCBjb2x1bW5zIGFuZCBhbGwgcm93cyBmcm9tIGEgYSB0YWJsZS4KCmBuYW1lcyh2YXJpYWJsZSlgIC0gUmV0dXJuIHRoZSBuYW1lcyAob3IgY29sdW1ucykgb2YgdGhlIHRhYmxlLgoKIyMjIERhdGEKIERhdGEgZmlsZTogW0lyaXMxQS5jc3ZdKGh0dHBzOi8vYml0YnVja2V0Lm9yZy9iZW56enovcGxvdGx5LXdvcmtzaG9wL3NyYy9tYXN0ZXIvSXJpczFBLmNzdikKYGBge3IgZGF0YS1pbXBvcnQsIGVjaG8gPSBUUlVFfQoKZ2V0d2QoKQoKZmlsZTEgPSByZWFkLmNzdigiSXJpczFBLmNzdiIpCnBsOHJlYWRlciA9IGZpbGUxCiMgVmlldyhwbDhyZWFkZXIpCgpwbDhyZWFkZXJbMSxdCnBsOHJlYWRlclssMV0KIApuYW1lcyhwbDhyZWFkZXIpWzFdCgpgYGAKIyMgUGxvdCB3aXRoIHBsb3RseQoKSW5zdGFsbCBwYWNrYWdlcyAtIHlvdSBjYW4gdXNlIGNvbW1hbmQgYGluc3RhbGwucGFja2FnZXMoInBhY2thZ2UtbmFtZSIpYC4gT3IgeW91IGNhbiB1c2UgcGFja2FnZSB0YWIgKGxvd2VyIHJpZ2h0IHBhbmUpIGFuZCBjbG9jayBpbnN0YWxsLgoKVG8gdXNlIHRoZSBwYWNrYWdlIChvciBsaWJyYXJ5KSB5b3UgY2FuIGNsaWNrIG9uIHNxdWFyZSBuZWFyIHBhY2thZ2UgbmFtZSBpbiB0aGUgcmlnaHQgd2luZG93LiBPciBiZXR0ZXIgdXNlIHRoZSBjb21tYW5kIGBsaWJyYXJ5KHBhY2thZ2UtbmFtZSlgLgoKW3Bsb3RseSBnUmVhdCBjaGVhdHNoZWV0XShodHRwczovL2ltYWdlcy5wbG90Lmx5L3Bsb3RseS1kb2N1bWVudGF0aW9uL2ltYWdlcy9yX2NoZWF0X3NoZWV0LnBkZikKYGBge3Igc3RhcnQtcGxvdGx5LCBlY2hvPVRSVUV9CiMgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikKbGlicmFyeShwbG90bHkpCgpwbG90X2x5KCBkYXRhID0gcGw4cmVhZGVyCiAgICAgICAgLHggPSBwbDhyZWFkZXIkVGltZS4ucy4KICAgICAgICAseSA9IHBsOHJlYWRlclssM10KICAgICAgICApIAoKYGBgCgoKYGBge3IgMSwgZWNobz1UUlVFfQpwbG90X2x5KCBkYXRhID0gcGw4cmVhZGVyCiAgICAgICAgLHR5cGUgPSAic2NhdHRlciIKICAgICAgICAsbW9kZSA9ICJsaW5lcyIKICAgICAgICAseCA9IHBsOHJlYWRlciRUaW1lLi5zLgogICAgICAgICx5ID0gcGw4cmVhZGVyWywzXQogICAgICAgICkgCmBgYAoKR29vZ2xlOiBbcGxvdGx5IGFkZCBsaW5lIHRvIHBsb3RdKCBodHRwczovL3d3dy5nb29nbGUuY28uaWwvc2VhcmNoP3E9cGxvdGx5K2FkZCtsaW5lK3RvK3Bsb3QpCiAgICAgICAgW3Bsb3RseSBhZGQgbmFtZSB0byBsZWdlbmRdKCBodHRwczovL3d3dy5nb29nbGUuY28uaWwvc2VhcmNoP3E9cGxvdGx5K2FkZCtuYW1lK3RvK2xlZ2VuZCkKICAgICAgICAKYGFkZF90cmFjZSgpYCAtIENvbW1hbmQgdG8gYWRkIG5ldyB0cmFjZSB0byBhIGdyYXBoLiBtb3JlIGluZm9ybWF0aW9uIGluIHRoZSBbZG9jdW1lbnRhdGlvbiBwYWdlXShodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvcGxvdGx5L3ZlcnNpb25zLzQuNy4xL3RvcGljcy9hZGRfdHJhY2UpLgoKQW5vdGhlciB3YXkgdG8gZ2V0IHRoZSBkb2N1bWVudGF0aW9uIGlzIHR5cGUgaW4gdGhlIGNvbnNvbGUgYD9mdW5jdGlvbi1uYW1lYCBhbmMgY2xpY2sgZW50ZXIuIG9yIGA/P3BhY2thZ2UtbmFtZWAgZm9yIHBhY2thZ2UgaGVscC4KYGBge3IgMiwgZWNobz1UUlVFfQpwID0gcGxvdF9seSggZGF0YSA9IHBsOHJlYWRlcgogICAgICAgICx0eXBlID0gInNjYXR0ZXIiCiAgICAgICAgLG1vZGUgPSAibGluZXMiCiAgICAgICAgLHggPSBwbDhyZWFkZXIkVGltZS4ucy4KICAgICAgICAseSA9IHBsOHJlYWRlclssM10KICAgICAgICAsbmFtZSA9IGNvbG5hbWVzKHBsOHJlYWRlcilbM10KICAgICAgICApIAphZGRfdHJhY2UocAogICAgICAgICAgLHkgPSBwbDhyZWFkZXJbLDRdCiAgICAgICAgICAsbmFtZSA9IGNvbG5hbWVzKHBsOHJlYWRlcilbNF0KICAgICAgICAgICkKYGBgCgoKCmBsYXlvdXQoKWAgLSBbZG9jdW1lbnRhdGlvbiBwYWdlXShodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvcGxvdGx5L3ZlcnNpb25zLzQuNy4xL3RvcGljcy9sYXlvdXQpCkdvb2dsZTogW3Bsb3RseSByIGFkZCBtYWluIHRpdGxlXSggaHR0cHM6Ly93d3cuZ29vZ2xlLmNvLmlsL3NlYXJjaD9xPXBsb3RseStyK2FkZCttYWluK3RpdGxlKQoKSW4gb3JkZXIgdG8gc2hvdyBjb3JyZWN0IHRpbWUgaW4gaG91cnMgSSBqdXN0IGR1dnVkZSB0aGUgc2Vjb25kcyB2YWx1ZSB3aXRoIGA2MCo2MD0zNjAwYC4KYGBge3IgMywgZWNobz1UUlVFfQoKcCA9IHBsb3RfbHkoIGRhdGEgPSBwbDhyZWFkZXIKICAgICAgICAsdHlwZSA9ICJzY2F0dGVyIgogICAgICAgICxtb2RlID0gImxpbmVzIgogICAgICAgICx4ID0gcGw4cmVhZGVyJFRpbWUuLnMuIC8zNjAwCiAgICAgICAgLHkgPSBwbDhyZWFkZXJbLDNdCiAgICAgICAgLG5hbWUgPSBjb2xuYW1lcyhwbDhyZWFkZXIpWzNdCiAgICAgICAgKSAKcCA9IGFkZF90cmFjZShwCiAgICAgICAgICAseSA9IHBsOHJlYWRlclssNF0KICAgICAgICAgICxuYW1lID0gY29sbmFtZXMocGw4cmVhZGVyKVs0XQogICAgICAgICAgKQpsYXlvdXQocAogICAgICAgLHRpdGxlID0gIkdyb3d0aCBjdXJ2ZSIKICAgICAgICx5YXhpcyA9IGxpc3QodGl0bGUgPSAiT0Q8c3ViPjYwMDwvc3ViPiBubSIpCiAgICAgICAseGF4aXMgPSBsaXN0KHRpdGxlID0gIlRpbWUgKEgpIikKICAgICAgICkKYGBgCiMgQ2xhc3MgMgojIyBFcnJvciBiYXJzCkdvb2dsZTogW3Bsb3RseSByIGVycm9yIGJhcnNdKCBodHRwczovL3d3dy5nb29nbGUuY28uaWwvc2VhcmNoP3E9cGxvdGx5K3IrZXJyb3IrYmFycykKYGBge3IgNCwgZWNobz1UUlVFfQpwID0gcGxvdF9seSggZGF0YSA9IHBsOHJlYWRlcgogICAgICAgICx0eXBlID0gInNjYXR0ZXIiCiAgICAgICAgLG1vZGUgPSAibGluZXMiCiAgICAgICAgLHggPSBwbDhyZWFkZXIkVGltZS4ucy4vMzYwMAogICAgICAgICx5ID0gcGw4cmVhZGVyWywzXQogICAgICAgICxuYW1lID0gY29sbmFtZXMocGw4cmVhZGVyKVszXQogICAgICAgICxlcnJvcl95ID0gfmxpc3QodmFsdWUgPSBwbDhyZWFkZXJbLDVdKQogICAgICAgIAogICAgICAgICkgCnAgPSBhZGRfdHJhY2UocAogICAgICAgICAgLHkgPSBwbDhyZWFkZXJbLDRdCiAgICAgICAgICAsbmFtZSA9IGNvbG5hbWVzKHBsOHJlYWRlcilbNF0KICAgICAgICAgICxlcnJvcl95ID0gfmxpc3QodmFsdWUgPSBwbDhyZWFkZXJbLDZdKQogICAgICAgICAgKQpsYXlvdXQocAogICAgICAgLHRpdGxlID0gIkdyb3d0aCBjdXJ2ZSIKICAgICAgICx5YXhpcyA9IGxpc3QodGl0bGUgPSAiT0Q8c3ViPjYwMDwvc3ViPiBubSIpCiAgICAgICAseGF4aXMgPSBsaXN0KHRpdGxlID0gIlRpbWUgKEgpIikKICAgICAgICkKCmBgYAojIyMgRXJyb3IgYXJlYQpHb29nbGU6IFtwbG90bHkgciBhcmVhXSggaHR0cHM6Ly93d3cuZ29vZ2xlLmNvLmlsL3NlYXJjaD9xPXBsb3RseStyK2FyZWEpCmBgYHtyIDUsIGVjaG89VFJVRX0KdXBwZXJfZXJyb3JCNCA9IHBsOHJlYWRlclssM10gKyBwbDhyZWFkZXJbLDVdCmxvd2VyX2Vycm9yQjQgPSBwbDhyZWFkZXJbLDNdIC0gcGw4cmVhZGVyWyw1XQp1cHBlcl9lcnJvckNhID0gcGw4cmVhZGVyWyw0XSArIHBsOHJlYWRlclssNl0KbG93ZXJfZXJyb3JDYSA9IHBsOHJlYWRlclssNF0gLSBwbDhyZWFkZXJbLDZdCgpwID0gcGxvdF9seSggZGF0YSA9IHBsOHJlYWRlcgogICAgICAgICx0eXBlID0gInNjYXR0ZXIiCiAgICAgICAgLG1vZGUgPSAibGluZXMiCiAgICAgICAgLHggPSBwbDhyZWFkZXIkVGltZS4ucy4vMzYwMAogICAgICAgICx5ID0gcGw4cmVhZGVyWywzXQogICAgICAgICxuYW1lID0gY29sbmFtZXMocGw4cmVhZGVyKVszXQopCnAgPSBhZGRfdHJhY2UocCwgeSA9IGxvd2VyX2Vycm9yQjQpCnAgPSBhZGRfdHJhY2UocCwgeSA9IHVwcGVyX2Vycm9yQjQsIGZpbGwgPSAidG9uZXh0eSIpCgpwID0gYWRkX3RyYWNlKHAsIHkgPSBwbDhyZWFkZXJbLDRdLCBuYW1lID0gY29sbmFtZXMocGw4cmVhZGVyKVs0XSkKcCA9IGFkZF90cmFjZShwLCB5ID0gbG93ZXJfZXJyb3JDYSkKcCA9IGFkZF90cmFjZShwLCB5ID0gdXBwZXJfZXJyb3JDYSwgZmlsbCA9ICJ0b25leHR5IikKCmxheW91dChwCiAgICAgICAsdGl0bGUgPSAiR3Jvd3RoIGN1cnZlIgogICAgICAgLHlheGlzID0gbGlzdCh0aXRsZSA9ICJPRDxzdWI+NjAwPC9zdWI+IG5tIikKICAgICAgICx4YXhpcyA9IGxpc3QodGl0bGUgPSAiVGltZSAoSCkiKQogICAgICAgKQpgYGAKCmBgYHtyIDYsIGVjaG89VFJVRX0KZWRnZSA9IGxpc3QoY29sb3IgPSAncmdiYSgwLDAsMCwwKScpCgpwID0gcGxvdF9seSggZGF0YSA9IHBsOHJlYWRlcgogICAgICAgICx0eXBlID0gInNjYXR0ZXIiCiAgICAgICAgLG1vZGUgPSAibGluZXMiCiAgICAgICAgLHggPSBwbDhyZWFkZXIkVGltZS4ucy4vMzYwMAogICAgICAgICx5ID0gcGw4cmVhZGVyWywzXQogICAgICAgICxuYW1lID0gY29sbmFtZXMocGw4cmVhZGVyKVszXQopCnAgPSBhZGRfdHJhY2UocCwgeSA9IGxvd2VyX2Vycm9yQjQsIHNob3dsZWdlbmQgPSBGLCBsaW5lID0gZWRnZSkKcCA9IGFkZF90cmFjZShwLCB5ID0gdXBwZXJfZXJyb3JCNCwgZmlsbCA9ICJ0b25leHR5IixzaG93bGVnZW5kID0gRiwgbGluZSA9IGVkZ2UsIGZpbGxjb2xvciA9ICdyZ2JhKDEsMSwxLDAuMSknKQoKcCA9IGFkZF90cmFjZShwLCB5ID0gcGw4cmVhZGVyWyw0XSxuYW1lID0gY29sbmFtZXMocGw4cmVhZGVyKVs0XSkKcCA9IGFkZF90cmFjZShwLCB5ID0gbG93ZXJfZXJyb3JDYSwgc2hvd2xlZ2VuZCA9IEYsIGxpbmUgPSBlZGdlKQpwID0gYWRkX3RyYWNlKHAsIHkgPSB1cHBlcl9lcnJvckNhLCBmaWxsID0gInRvbmV4dHkiLHNob3dsZWdlbmQgPSBGLCBsaW5lID0gZWRnZSwgZmlsbGNvbG9yID0gJ3JnYmEoMSwxLDEsMC4xKScpCgpsYXlvdXQocAogICAgICAgLHRpdGxlID0gIkdyb3d0aCBjdXJ2ZSIKICAgICAgICx5YXhpcyA9IGxpc3QodGl0bGUgPSAiT0Q8c3ViPjYwMDwvc3ViPiBubSIpCiAgICAgICAseGF4aXMgPSBsaXN0KHRpdGxlID0gIlRpbWUgKEgpIikKICAgICAgICkKYGBgCgpObyBncmlkIG5vIHplcm9saW5lLgpgYGB7ciA3LCBlY2hvPVRSVUV9CnAgPSBwbG90X2x5KCBkYXRhID0gcGw4cmVhZGVyCiAgICAgICAgLHR5cGUgPSAic2NhdHRlciIKICAgICAgICAsbW9kZSA9ICJsaW5lcyIKICAgICAgICAseCA9IHBsOHJlYWRlciRUaW1lLi5zLi8zNjAwCiAgICAgICAgLHkgPSBwbDhyZWFkZXJbLDNdCiAgICAgICAgLG5hbWUgPSBjb2xuYW1lcyhwbDhyZWFkZXIpWzNdCikKcCA9IGFkZF90cmFjZShwLCB5ID0gbG93ZXJfZXJyb3JCNCwgc2hvd2xlZ2VuZCA9IEYsIGxpbmUgPSBlZGdlKQpwID0gYWRkX3RyYWNlKHAsIHkgPSB1cHBlcl9lcnJvckI0LCBmaWxsID0gInRvbmV4dHkiLHNob3dsZWdlbmQgPSBGLCBsaW5lID0gZWRnZSwgZmlsbGNvbG9yID0gJ3JnYmEoMSwxLDEsMC4xKScpCgpwID0gYWRkX3RyYWNlKHAsIHkgPSBwbDhyZWFkZXJbLDRdLG5hbWUgPSBjb2xuYW1lcyhwbDhyZWFkZXIpWzRdKQpwID0gYWRkX3RyYWNlKHAsIHkgPSBsb3dlcl9lcnJvckNhLCBzaG93bGVnZW5kID0gRiwgbGluZSA9IGVkZ2UpCnAgPSBhZGRfdHJhY2UocCwgeSA9IHVwcGVyX2Vycm9yQ2EsIGZpbGwgPSAidG9uZXh0eSIsc2hvd2xlZ2VuZCA9IEYsIGxpbmUgPSBlZGdlLCBmaWxsY29sb3IgPSAncmdiYSgxLDEsMSwwLjEpJykKCmxheW91dChwCiAgICAgICAsdGl0bGUgPSAiR3Jvd3RoIGN1cnZlIgogICAgICAgLHlheGlzID0gbGlzdCh0aXRsZSA9ICJPRDxzdWI+NjAwPC9zdWI+IG5tIiwgc2hvd2dyaWQgPSBGQUxTRSkKICAgICAgICx4YXhpcyA9IGxpc3QodGl0bGUgPSAiVGltZSAoSCkiLCBzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEYpCiAgICAgICApCgpgYGAKIyMgTG9vcHMKYGBge3J9ClZpZXcocGw4cmVhZGVyKQpgYGAKCgpgYGB7cn0Kc2VxKGZyb20gPSAxLCB0byA9IDM1LCBieSA9IDIuMykKYGBgCgpgYGB7cn0KZm9yKGkgaW4gc2VxKGZyb20gPSAzLCB0byA9IDI5LCBieSA9IDQpKQp7cHJpbnQobmFtZXMocGw4cmVhZGVyKVtpXSl9CmBgYAoKCmBgYHtyIDgsIGVjaG89VFJVRX0KcCA9IHBsb3RfbHkoIGRhdGEgPSBwbDhyZWFkZXIKICAgICAgICAsdHlwZSA9ICJzY2F0dGVyIgogICAgICAgICxtb2RlID0gImxpbmVzIgopCgpmb3IoaSBpbiBzZXEoZnJvbSA9IDMsIHRvID0gMjksIGJ5ID0gNCkpewpqPWkrMQp1cHBlcl9lcnJvckI0ID0gcGw4cmVhZGVyWyxpXSArIHBsOHJlYWRlclssaSsyXQpsb3dlcl9lcnJvckI0ID0gcGw4cmVhZGVyWyxpXSAtIHBsOHJlYWRlclssaSsyXQpsb3dlcl9lcnJvckI0W2xvd2VyX2Vycm9yQjQ8MF0gPSAwCnVwcGVyX2Vycm9yQ2EgPSBwbDhyZWFkZXJbLGpdICsgcGw4cmVhZGVyWyxqKzJdCmxvd2VyX2Vycm9yQ2EgPSBwbDhyZWFkZXJbLGpdIC0gcGw4cmVhZGVyWyxqKzJdCmxvd2VyX2Vycm9yQ2FbbG93ZXJfZXJyb3JDYTwwXSA9IDAKCgpwID0gYWRkX3RyYWNlKHAsIHkgPSBwbDhyZWFkZXJbLGldLCBuYW1lID0gY29sbmFtZXMocGw4cmVhZGVyKVtpXSwgY29sb3IgPSBiYmJbaV0pCnAgPSBhZGRfdHJhY2UocCwgeSA9IGxvd2VyX2Vycm9yQjQsIHNob3dsZWdlbmQgPSBGLCBsaW5lID0gZWRnZSkKcCA9IGFkZF90cmFjZShwLCB5ID0gdXBwZXJfZXJyb3JCNCwgZmlsbCA9ICJ0b25leHR5IixzaG93bGVnZW5kID0gRiwgbGluZSA9IGVkZ2UsIGZpbGxjb2xvciA9ICdyZ2JhKDEsMSwxLDAuMSknKQoKcCA9IGFkZF90cmFjZShwLCB5ID0gcGw4cmVhZGVyWyxqXSxuYW1lID0gY29sbmFtZXMocGw4cmVhZGVyKVtqXSwgY29sb3IgPSBiYmJbaV0pCnAgPSBhZGRfdHJhY2UocCwgeSA9IGxvd2VyX2Vycm9yQ2EsIHNob3dsZWdlbmQgPSBGLCBsaW5lID0gZWRnZSkKcCA9IGFkZF90cmFjZShwLCB5ID0gdXBwZXJfZXJyb3JDYSwgZmlsbCA9ICJ0b25leHR5IixzaG93bGVnZW5kID0gRiwgbGluZSA9IGVkZ2UsIGZpbGxjb2xvciA9ICdyZ2JhKDEsMSwxLDAuMSknKQp9CgpsYXlvdXQocAogICAgICAgLHRpdGxlID0gIkdyb3d0aCBjdXJ2ZSIKICAgICAgICx5YXhpcyA9IGxpc3QodGl0bGUgPSAiT0Q8c3ViPjYwMDwvc3ViPiBubSIsIHNob3dncmlkID0gRkFMU0UpCiAgICAgICAseGF4aXMgPSBsaXN0KHRpdGxlID0gIlRpbWUgKEgpIiwgc2hvd2dyaWQgPSBGQUxTRSwgemVyb2xpbmUgPSBGKSkKCmBgYApEYXRhIGZpbGU6IFtJcmlzMkEuY3N2XShodHRwczovL2JpdGJ1Y2tldC5vcmcvYmVuenp6L3Bsb3RseS13b3Jrc2hvcC9zcmMvbWFzdGVyL0lyaXMyQS5jc3YpCmBgYHtyIDksIGVjaG89VFJVRX0KCmZpbGUyID0gcmVhZC5jc3YoIklyaXMyQS5jc3YiKQpwbDhyZWFkZXIgPSBmaWxlMgoKZGltKHBsOHJlYWRlcikKCnAgPSBwbG90X2x5KCBkYXRhID0gcGw4cmVhZGVyCiAgICAgICAgLHR5cGUgPSAic2NhdHRlciIKICAgICAgICAsbW9kZSA9ICJsaW5lcyIKKQoKZm9yKGkgaW4gc2VxKGZyb20gPSAyLCB0byA9IDI1LCBieSA9IDQpKXsKaj1pKzEKdXBwZXJfZXJyb3JCNCA9IHBsOHJlYWRlclssaV0gKyBwbDhyZWFkZXJbLGkrMl0KbG93ZXJfZXJyb3JCNCA9IHBsOHJlYWRlclssaV0gLSBwbDhyZWFkZXJbLGkrMl0KbG93ZXJfZXJyb3JCNFtsb3dlcl9lcnJvckI0PDBdID0gMAp1cHBlcl9lcnJvckNhID0gcGw4cmVhZGVyWyxqXSArIHBsOHJlYWRlclssaisyXQpsb3dlcl9lcnJvckNhID0gcGw4cmVhZGVyWyxqXSAtIHBsOHJlYWRlclssaisyXQpsb3dlcl9lcnJvckNhW2xvd2VyX2Vycm9yQ2E8MF0gPSAwCgoKcCA9IGFkZF90cmFjZShwLCB5ID0gcGw4cmVhZGVyWyxpXSxuYW1lID0gY29sbmFtZXMocGw4cmVhZGVyKVtpXSkKcCA9IGFkZF90cmFjZShwLCB5ID0gbG93ZXJfZXJyb3JCNCwgc2hvd2xlZ2VuZCA9IEYsIGxpbmUgPSBlZGdlKQpwID0gYWRkX3RyYWNlKHAsIHkgPSB1cHBlcl9lcnJvckI0LCBmaWxsID0gInRvbmV4dHkiLHNob3dsZWdlbmQgPSBGLCBsaW5lID0gZWRnZSwgZmlsbGNvbG9yID0gJ3JnYmEoMSwxLDEsMC4xKScpCgpwID0gYWRkX3RyYWNlKHAsIHkgPSBwbDhyZWFkZXJbLGpdLG5hbWUgPSBjb2xuYW1lcyhwbDhyZWFkZXIpW2pdKQpwID0gYWRkX3RyYWNlKHAsIHkgPSBsb3dlcl9lcnJvckNhLCBzaG93bGVnZW5kID0gRiwgbGluZSA9IGVkZ2UpCnAgPSBhZGRfdHJhY2UocCwgeSA9IHVwcGVyX2Vycm9yQ2EsIGZpbGwgPSAidG9uZXh0eSIsc2hvd2xlZ2VuZCA9IEYsIGxpbmUgPSBlZGdlLCBmaWxsY29sb3IgPSAncmdiYSgxLDEsMSwwLjEpJykKfQoKbGF5b3V0KHAKICAgICAgICx0aXRsZSA9ICJHcm93dGggY3VydmUiCiAgICAgICAseWF4aXMgPSBsaXN0KHRpdGxlID0gIk9EPHN1Yj42MDA8L3N1Yj4gbm0iLCBzaG93Z3JpZCA9IEZBTFNFKQogICAgICAgLHhheGlzID0gbGlzdCh0aXRsZSA9ICJUaW1lIChIKSIsIHNob3dncmlkID0gRkFMU0UsIHplcm9saW5lID0gRikpCgpgYGAKCkRhdGEgZmlsZTogW0lyaXMzQS5jc3ZdKGh0dHBzOi8vYml0YnVja2V0Lm9yZy9iZW56enovcGxvdGx5LXdvcmtzaG9wL3NyYy9tYXN0ZXIvSXJpczNBLmNzdikKCkdvb2dsZTogW3IgcmVhZCBjc3Ygc2tpcCBlbXB0eSBsaW5lc10oaHR0cHM6Ly93d3cuZ29vZ2xlLmNvLmlsL3NlYXJjaD9xPXIrcmVhZCtjc3Yrc2tpcCtlbXB0eStsaW5lcykKVGhlcmUgaXMgc29tZSBwcm9ibGVtIGFib3V0IHN0ZApgYGB7ciAxMCwgZWNobz1UUlVFfQoKIyBmaWxlMyA9IHJlYWQuY3N2KCJJcmlzM0EuY3N2IikKIyBmaWxlMyA9IHJlYWQuY3N2KGZpbGUgPSAiSXJpczNBLmNzdiIgLHNraXAgPSBhcy5udW1lcmljKHJvd25hbWVzKGZpbGUzW3doaWNoKGZpbGUzWywxXSE9JycpLF0pWzFdKSkKIyBwbDhyZWFkZXIgPSBmaWxlM1szOmxlbmd0aChmaWxlMyksXQojIAojIFZpZXcocGw4cmVhZGVyKQoKcCA9IHBsb3RfbHkoIGRhdGEgPSBwbDhyZWFkZXIKICAgICAgICAsdHlwZSA9ICJzY2F0dGVyIgogICAgICAgICxtb2RlID0gImxpbmVzIgopCgpmb3IoaSBpbiBzZXEoZnJvbSA9IDIsIHRvID0gMjksIGJ5ID0gNCkpewpqPWkrMQp1cHBlcl9lcnJvckI0ID0gcGw4cmVhZGVyWyxpXSArIHBsOHJlYWRlclssaSsyXQpsb3dlcl9lcnJvckI0ID0gcGw4cmVhZGVyWyxpXSAtIHBsOHJlYWRlclssaSsyXQpsb3dlcl9lcnJvckI0W2xvd2VyX2Vycm9yQjQ8MF0gPSAwCnVwcGVyX2Vycm9yQ2EgPSBwbDhyZWFkZXJbLGpdICsgcGw4cmVhZGVyWyxqKzJdCmxvd2VyX2Vycm9yQ2EgPSBwbDhyZWFkZXJbLGpdIC0gcGw4cmVhZGVyWyxqKzJdCmxvd2VyX2Vycm9yQ2FbbG93ZXJfZXJyb3JDYTwwXSA9IDAKCgpwID0gYWRkX3RyYWNlKHAsIHkgPSBwbDhyZWFkZXJbLGldLG5hbWUgPSBjb2xuYW1lcyhwbDhyZWFkZXIpW2ldKQpwID0gYWRkX3RyYWNlKHAsIHkgPSBsb3dlcl9lcnJvckI0LCBzaG93bGVnZW5kID0gRiwgbGluZSA9IGVkZ2UpCnAgPSBhZGRfdHJhY2UocCwgeSA9IHVwcGVyX2Vycm9yQjQsIGZpbGwgPSAidG9uZXh0eSIsc2hvd2xlZ2VuZCA9IEYsIGxpbmUgPSBlZGdlLCBmaWxsY29sb3IgPSAncmdiYSgxLDEsMSwwLjEpJykKCnAgPSBhZGRfdHJhY2UocCwgeSA9IHBsOHJlYWRlclssal0sbmFtZSA9IGNvbG5hbWVzKHBsOHJlYWRlcilbal0pCnAgPSBhZGRfdHJhY2UocCwgeSA9IGxvd2VyX2Vycm9yQ2EsIHNob3dsZWdlbmQgPSBGLCBsaW5lID0gZWRnZSkKcCA9IGFkZF90cmFjZShwLCB5ID0gdXBwZXJfZXJyb3JDYSwgZmlsbCA9ICJ0b25leHR5IixzaG93bGVnZW5kID0gRiwgbGluZSA9IGVkZ2UsIGZpbGxjb2xvciA9ICdyZ2JhKDEsMSwxLDAuMSknKQp9CgpsYXlvdXQocAogICAgICAgLHRpdGxlID0gIkdyb3d0aCBjdXJ2ZSIKICAgICAgICx5YXhpcyA9IGxpc3QodGl0bGUgPSAiT0Q8c3ViPjYwMDwvc3ViPiBubSIsIHNob3dncmlkID0gRkFMU0UpCiAgICAgICAseGF4aXMgPSBsaXN0KHRpdGxlID0gIlRpbWUgKEgpIiwgc2hvd2dyaWQgPSBGQUxTRSwgemVyb2xpbmUgPSBGKSkKCmBgYAo=