library(tidyverse)
library(ggplot2)
library(dplyr)
library(mgcv)
library(broom)

Import data

Bash pre-process the data files

The data files are organized in three folders under data/d06..., each corresponding to a replicate experiment of the same design. Within each folder, the separate CSV files are the different time points. In this case because the time point information is already encoded in the files, to make the parsing easier, we will first concatenate all the files in each folder into a single one. To make sure that one and only one header is included in the concatenated file, we use a trick thanks to this post

cd data
for i in d06*;
do
  awk '(NR == 1) || (FNR > 1)' $i/*.csv > ./merge-${i%-statistics}.csv
done
gzip merge-*.csv
cd ..

Import data into R

files <- dir("data", pattern = "merge-*") # get the file names of the merged
files <- file.path("data", files)         # this appends the directory to the file names
names(files) <- paste0("Rep", 1:3)        # name the replicates
tp <- c("0min",  "30min", "60min", "90min", "120min", "150min",  "180min", "210min", "240min") # ordered time points

# import and process the data to the format we want
dat <- files %>% 
  map(~read_csv(., na = c("", "NA", "N/A"), col_types = cols())) %>%   
  # ~read_csv(): apply read_csv() function to each file, returns a list
  #   using the readr::read_csv() is much faster than the base read.csv
  #   it doesn't "repair" the column names, like "X Parameter" -> "X.Parameter"
  #   to refer to them, use the backsticks, like `X Parameter`
  # na = c(): the output files use N/A to encode missing data
  #   to be able to read all data in one go, we need to specify that
  # col_types = cols(): this tells the function to guess the colum types
  bind_rows(.id = "Replicate") %>%
  # bind all the rows from the list items into a single data frame
  filter(`X Parameter` == "BL1-H", is.na(`Y Parameter`)) %>% 
  # only save the GFP channel, ane make sure that Y parameter is NA
  select(Replicate, Group, Sample, Count, median = `X Median`, peak =`X Peak`, 
         sd = `X SD`, cv = `X %CV`, rCV = `X %rCV`) %>% 
  mutate(Group = ordered(Group, levels = tp)) %>% # make sure time points are ordered
  arrange(Group) # sort by time points

write_csv(dat, file = "data/20210616-Msn2-Msn4-KO-flow-data.csv")

Subset the dataset and merge with the genotype information:

# get genotype info
Genotype <- read.csv("data/Genotype.csv")

## select rows based on genotype info
pi_condition <- Genotype %>% filter(Treatment == "no_Pi")

pi.dat <- dat %>% 
  filter(Sample %in% pi_condition$Sample) %>% 
  select(time = Group, Sample, replicate = Replicate, median) %>% 
  left_join(pi_condition, by = "Sample") %>% 
  select(sample = Sample, everything(), -Treatment) %>% 
  arrange(time, genotype, replicate)

write_csv(pi.dat, file = "data/20210616-Msn2-Msn4-KO-flow-data.csv.gz")

Analysis

Visualize the data

pi.dat %>% 
  ggplot(aes(x = time, y = median, color = replicate)) + geom_point(size = 0.2) + 
  facet_wrap(~genotype) + stat_summary(fun = "median", geom = "point", size = 2) +
  stat_smooth(aes(x = as.numeric(time)), se = FALSE) +
  theme_bw()
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Since the three replicates are rather similar to each other, let’s treat them as one large pool, and combine the four genotypes

pi.dat %>% 
  ggplot(aes(x = time, y = median, color = genotype)) + geom_point(size = 0.2) + 
  stat_summary(fun = "mean", geom = "point", size = 2) +
  stat_smooth(aes(x = as.numeric(time)), se = FALSE) +
  theme_bw()
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Data transformation

We want to transform the median fluorescent intensity into fold change relative to time point 0 for each genotype. Then we would like to normalize that for each non-wt genotype by the wild type fold change at each time point. The goal is to highlight the deficiency in gene induction in the knock out.

# first let's calculate the fold change by dividing the median fluorescent indensity of each genotype at each time point by the mean MFI for that genotype at time point 0.
# we begin by calculating the baseline for each genotype
pi.summary <- pi.dat %>% 
  group_by(genotype, time) %>% 
  summarize(baseline = mean(median)) %>% 
  filter(time == "0min") %>% 
  select(-time)
`summarise()` has grouped output by 'genotype'. You can override using the `.groups` argument.
# next we calculate the fold change
pi.dat1 <- pi.dat %>% 
  left_join(pi.summary, by = "genotype") %>% 
  mutate(fc = median / baseline)
# for each time point, we calculate the mean fold change for the wild type strain  
pi.wt.fc <- pi.dat1 %>% 
  filter(genotype == "wt") %>% 
  group_by(time) %>% 
  summarize(wt.mFC = mean(fc))
# finally, we normalize the non-wt strains by the wild type mean fold change at each time point
pi.dat1 <- pi.dat1 %>% 
  left_join(pi.wt.fc, by = "time") %>% 
  mutate(normFC = fc / wt.mFC)

plot the normalized fold changes

pi.dat1 %>% 
  ggplot(aes(x = time, y = normFC, color = genotype)) + geom_point(size = 0.2) + 
  stat_summary(fun = "mean", geom = "point", size = 2) +
  stat_smooth(aes(x = as.numeric(time)), se = FALSE) +
  ylab("fold change relative to 0 min, normalized to wild type") +
  theme_bw()
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

We could perform linear regression on the data to test if the slope is significantly different from zero. We use a “nest-map-unnest” workflow (see this link)

pi.dat1 %>% 
  filter(genotype != "wt") %>% 
  mutate(time = as.numeric(time)) %>% 
  group_by(genotype) %>% 
  nest() %>% 
  mutate(
    fit = map(data, ~ lm(normFC ~ time, data = .x)),
    tidied = map(fit, tidy)
  ) %>% 
  unnest(tidied)
NA

For each non-wt genotype, we can read the estimates of the intercept and slope (time) and the significance of them. We see that msn2∆ has a slope that is not siginificantly different from zero while both msn4∆ and msn2∆ msn4∆ show significant slopes that are below zero, indicating that they both show a less effective induction of CTA1 compared with the wild type. This allows us to conclude that most likely Msn4 is a positive regulator of CTA1 in C. glabrata

LS0tCnRpdGxlOiAiZGF0YV9jb2xsZWN0aW9uX3Zpc3VhbGl6aW5nIgphdXRob3I6ICJKaW55ZSBMaWFuZyIKZGF0ZTogIkp1bmUgMTMsIDIwMjEiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogNQogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkobWdjdikKbGlicmFyeShicm9vbSkKYGBgCgojIyBJbXBvcnQgZGF0YQojIyMgQmFzaCBwcmUtcHJvY2VzcyB0aGUgZGF0YSBmaWxlcwpUaGUgZGF0YSBmaWxlcyBhcmUgb3JnYW5pemVkIGluIHRocmVlIGZvbGRlcnMgdW5kZXIgYGRhdGEvZDA2Li4uYCwgZWFjaCBjb3JyZXNwb25kaW5nIHRvIGEgcmVwbGljYXRlIGV4cGVyaW1lbnQgb2YgdGhlIHNhbWUgZGVzaWduLiBXaXRoaW4gZWFjaCBmb2xkZXIsIHRoZSBzZXBhcmF0ZSBDU1YgZmlsZXMgYXJlIHRoZSBkaWZmZXJlbnQgdGltZSBwb2ludHMuIEluIHRoaXMgY2FzZSBiZWNhdXNlIHRoZSB0aW1lIHBvaW50IGluZm9ybWF0aW9uIGlzIGFscmVhZHkgZW5jb2RlZCBpbiB0aGUgZmlsZXMsIHRvIG1ha2UgdGhlIHBhcnNpbmcgZWFzaWVyLCB3ZSB3aWxsIGZpcnN0IGNvbmNhdGVuYXRlIGFsbCB0aGUgZmlsZXMgaW4gZWFjaCBmb2xkZXIgaW50byBhIHNpbmdsZSBvbmUuIFRvIG1ha2Ugc3VyZSB0aGF0IG9uZSBhbmQgb25seSBvbmUgaGVhZGVyIGlzIGluY2x1ZGVkIGluIHRoZSBjb25jYXRlbmF0ZWQgZmlsZSwgd2UgdXNlIGEgdHJpY2sgdGhhbmtzIHRvIFt0aGlzIHBvc3RdKGh0dHBzOi8vYXBwbGUuc3RhY2tleGNoYW5nZS5jb20vcXVlc3Rpb25zLzgwNjExL21lcmdpbmctbXVsdGlwbGUtY3N2LWZpbGVzLXdpdGhvdXQtbWVyZ2luZy10aGUtaGVhZGVyKQoKYGBge2Jhc2h9CmNkIGRhdGEKZm9yIGkgaW4gZDA2KjsKZG8KICBhd2sgJyhOUiA9PSAxKSB8fCAoRk5SID4gMSknICRpLyouY3N2ID4gLi9tZXJnZS0ke2klLXN0YXRpc3RpY3N9LmNzdgpkb25lCmd6aXAgbWVyZ2UtKi5jc3YKY2QgLi4KYGBgCgojIyMgSW1wb3J0IGRhdGEgaW50byBSCmBgYHtyfQpmaWxlcyA8LSBkaXIoImRhdGEiLCBwYXR0ZXJuID0gIm1lcmdlLSoiKSAjIGdldCB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgbWVyZ2VkCmZpbGVzIDwtIGZpbGUucGF0aCgiZGF0YSIsIGZpbGVzKSAgICAgICAgICMgdGhpcyBhcHBlbmRzIHRoZSBkaXJlY3RvcnkgdG8gdGhlIGZpbGUgbmFtZXMKbmFtZXMoZmlsZXMpIDwtIHBhc3RlMCgiUmVwIiwgMTozKSAgICAgICAgIyBuYW1lIHRoZSByZXBsaWNhdGVzCnRwIDwtIGMoIjBtaW4iLCAgIjMwbWluIiwgIjYwbWluIiwgIjkwbWluIiwgIjEyMG1pbiIsICIxNTBtaW4iLCAgIjE4MG1pbiIsICIyMTBtaW4iLCAiMjQwbWluIikgIyBvcmRlcmVkIHRpbWUgcG9pbnRzCgojIGltcG9ydCBhbmQgcHJvY2VzcyB0aGUgZGF0YSB0byB0aGUgZm9ybWF0IHdlIHdhbnQKZGF0IDwtIGZpbGVzICU+JSAKICBtYXAofnJlYWRfY3N2KC4sIG5hID0gYygiIiwgIk5BIiwgIk4vQSIpLCBjb2xfdHlwZXMgPSBjb2xzKCkpKSAlPiUgICAKICAjIH5yZWFkX2NzdigpOiBhcHBseSByZWFkX2NzdigpIGZ1bmN0aW9uIHRvIGVhY2ggZmlsZSwgcmV0dXJucyBhIGxpc3QKICAjICAgdXNpbmcgdGhlIHJlYWRyOjpyZWFkX2NzdigpIGlzIG11Y2ggZmFzdGVyIHRoYW4gdGhlIGJhc2UgcmVhZC5jc3YKICAjICAgaXQgZG9lc24ndCAicmVwYWlyIiB0aGUgY29sdW1uIG5hbWVzLCBsaWtlICJYIFBhcmFtZXRlciIgLT4gIlguUGFyYW1ldGVyIgogICMgICB0byByZWZlciB0byB0aGVtLCB1c2UgdGhlIGJhY2tzdGlja3MsIGxpa2UgYFggUGFyYW1ldGVyYAogICMgbmEgPSBjKCk6IHRoZSBvdXRwdXQgZmlsZXMgdXNlIE4vQSB0byBlbmNvZGUgbWlzc2luZyBkYXRhCiAgIyAgIHRvIGJlIGFibGUgdG8gcmVhZCBhbGwgZGF0YSBpbiBvbmUgZ28sIHdlIG5lZWQgdG8gc3BlY2lmeSB0aGF0CiAgIyBjb2xfdHlwZXMgPSBjb2xzKCk6IHRoaXMgdGVsbHMgdGhlIGZ1bmN0aW9uIHRvIGd1ZXNzIHRoZSBjb2x1bSB0eXBlcwogIGJpbmRfcm93cyguaWQgPSAiUmVwbGljYXRlIikgJT4lCiAgIyBiaW5kIGFsbCB0aGUgcm93cyBmcm9tIHRoZSBsaXN0IGl0ZW1zIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZQogIGZpbHRlcihgWCBQYXJhbWV0ZXJgID09ICJCTDEtSCIsIGlzLm5hKGBZIFBhcmFtZXRlcmApKSAlPiUgCiAgIyBvbmx5IHNhdmUgdGhlIEdGUCBjaGFubmVsLCBhbmUgbWFrZSBzdXJlIHRoYXQgWSBwYXJhbWV0ZXIgaXMgTkEKICBzZWxlY3QoUmVwbGljYXRlLCBHcm91cCwgU2FtcGxlLCBDb3VudCwgbWVkaWFuID0gYFggTWVkaWFuYCwgcGVhayA9YFggUGVha2AsIAogICAgICAgICBzZCA9IGBYIFNEYCwgY3YgPSBgWCAlQ1ZgLCByQ1YgPSBgWCAlckNWYCkgJT4lIAogIG11dGF0ZShHcm91cCA9IG9yZGVyZWQoR3JvdXAsIGxldmVscyA9IHRwKSkgJT4lICMgbWFrZSBzdXJlIHRpbWUgcG9pbnRzIGFyZSBvcmRlcmVkCiAgYXJyYW5nZShHcm91cCkgIyBzb3J0IGJ5IHRpbWUgcG9pbnRzCmBgYAoKIyMjIFN1YnNldCB0aGUgZGF0YXNldCBhbmQgbWVyZ2Ugd2l0aCB0aGUgZ2Vub3R5cGUgaW5mb3JtYXRpb246CmBgYHtyfQojIGdldCBnZW5vdHlwZSBpbmZvCkdlbm90eXBlIDwtIHJlYWQuY3N2KCJkYXRhL0dlbm90eXBlLmNzdiIpCgojIyBzZWxlY3Qgcm93cyBiYXNlZCBvbiBnZW5vdHlwZSBpbmZvCnBpX2NvbmRpdGlvbiA8LSBHZW5vdHlwZSAlPiUgZmlsdGVyKFRyZWF0bWVudCA9PSAibm9fUGkiKQoKcGkuZGF0IDwtIGRhdCAlPiUgCiAgZmlsdGVyKFNhbXBsZSAlaW4lIHBpX2NvbmRpdGlvbiRTYW1wbGUpICU+JSAKICBzZWxlY3QodGltZSA9IEdyb3VwLCBTYW1wbGUsIHJlcGxpY2F0ZSA9IFJlcGxpY2F0ZSwgbWVkaWFuKSAlPiUgCiAgbGVmdF9qb2luKHBpX2NvbmRpdGlvbiwgYnkgPSAiU2FtcGxlIikgJT4lIAogIHNlbGVjdChzYW1wbGUgPSBTYW1wbGUsIGV2ZXJ5dGhpbmcoKSwgLVRyZWF0bWVudCkgJT4lIAogIGFycmFuZ2UodGltZSwgZ2Vub3R5cGUsIHJlcGxpY2F0ZSkKCndyaXRlX2NzdihwaS5kYXQsIGZpbGUgPSAiZGF0YS8yMDIxMDYxNi1Nc24yLU1zbjQtS08tZmxvdy1kYXRhLmNzdi5neiIpCmBgYAoKIyMgQW5hbHlzaXMKIyMjIFZpc3VhbGl6ZSB0aGUgZGF0YQpgYGB7cn0KcGkuZGF0ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB0aW1lLCB5ID0gbWVkaWFuLCBjb2xvciA9IHJlcGxpY2F0ZSkpICsgZ2VvbV9wb2ludChzaXplID0gMC4yKSArIAogIGZhY2V0X3dyYXAofmdlbm90eXBlKSArIHN0YXRfc3VtbWFyeShmdW4gPSAibWVkaWFuIiwgZ2VvbSA9ICJwb2ludCIsIHNpemUgPSAyKSArCiAgc3RhdF9zbW9vdGgoYWVzKHggPSBhcy5udW1lcmljKHRpbWUpKSwgc2UgPSBGQUxTRSkgKwogIHRoZW1lX2J3KCkKYGBgClNpbmNlIHRoZSB0aHJlZSByZXBsaWNhdGVzIGFyZSByYXRoZXIgc2ltaWxhciB0byBlYWNoIG90aGVyLCBsZXQncyB0cmVhdCB0aGVtIGFzIG9uZSBsYXJnZSBwb29sLCBhbmQgY29tYmluZSB0aGUgZm91ciBnZW5vdHlwZXMKYGBge3J9CnBpLmRhdCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gdGltZSwgeSA9IG1lZGlhbiwgY29sb3IgPSBnZW5vdHlwZSkpICsgZ2VvbV9wb2ludChzaXplID0gMC4yKSArIAogIHN0YXRfc3VtbWFyeShmdW4gPSAibWVhbiIsIGdlb20gPSAicG9pbnQiLCBzaXplID0gMikgKwogIHN0YXRfc21vb3RoKGFlcyh4ID0gYXMubnVtZXJpYyh0aW1lKSksIHNlID0gRkFMU0UpICsKICB0aGVtZV9idygpCmBgYAoKIyMjIERhdGEgdHJhbnNmb3JtYXRpb24KV2Ugd2FudCB0byB0cmFuc2Zvcm0gdGhlIG1lZGlhbiBmbHVvcmVzY2VudCBpbnRlbnNpdHkgaW50byBmb2xkIGNoYW5nZSByZWxhdGl2ZSB0byB0aW1lIHBvaW50IDAgZm9yIGVhY2ggZ2Vub3R5cGUuIFRoZW4gd2Ugd291bGQgbGlrZSB0byBub3JtYWxpemUgdGhhdCBmb3IgZWFjaCBub24td3QgZ2Vub3R5cGUgYnkgdGhlIHdpbGQgdHlwZSBmb2xkIGNoYW5nZSBhdCBlYWNoIHRpbWUgcG9pbnQuIFRoZSBnb2FsIGlzIHRvIGhpZ2hsaWdodCB0aGUgZGVmaWNpZW5jeSBpbiBnZW5lIGluZHVjdGlvbiBpbiB0aGUga25vY2sgb3V0LgoKYGBge3J9CiMgZmlyc3QgbGV0J3MgY2FsY3VsYXRlIHRoZSBmb2xkIGNoYW5nZSBieSBkaXZpZGluZyB0aGUgbWVkaWFuIGZsdW9yZXNjZW50IGluZGVuc2l0eSBvZiBlYWNoIGdlbm90eXBlIGF0IGVhY2ggdGltZSBwb2ludCBieSB0aGUgbWVhbiBNRkkgZm9yIHRoYXQgZ2Vub3R5cGUgYXQgdGltZSBwb2ludCAwLgojIHdlIGJlZ2luIGJ5IGNhbGN1bGF0aW5nIHRoZSBiYXNlbGluZSBmb3IgZWFjaCBnZW5vdHlwZQpwaS5zdW1tYXJ5IDwtIHBpLmRhdCAlPiUgCiAgZ3JvdXBfYnkoZ2Vub3R5cGUsIHRpbWUpICU+JSAKICBzdW1tYXJpemUoYmFzZWxpbmUgPSBtZWFuKG1lZGlhbikpICU+JSAKICBmaWx0ZXIodGltZSA9PSAiMG1pbiIpICU+JSAKICBzZWxlY3QoLXRpbWUpCiMgbmV4dCB3ZSBjYWxjdWxhdGUgdGhlIGZvbGQgY2hhbmdlCnBpLmRhdDEgPC0gcGkuZGF0ICU+JSAKICBsZWZ0X2pvaW4ocGkuc3VtbWFyeSwgYnkgPSAiZ2Vub3R5cGUiKSAlPiUgCiAgbXV0YXRlKGZjID0gbWVkaWFuIC8gYmFzZWxpbmUpCiMgZm9yIGVhY2ggdGltZSBwb2ludCwgd2UgY2FsY3VsYXRlIHRoZSBtZWFuIGZvbGQgY2hhbmdlIGZvciB0aGUgd2lsZCB0eXBlIHN0cmFpbiAgCnBpLnd0LmZjIDwtIHBpLmRhdDEgJT4lIAogIGZpbHRlcihnZW5vdHlwZSA9PSAid3QiKSAlPiUgCiAgZ3JvdXBfYnkodGltZSkgJT4lIAogIHN1bW1hcml6ZSh3dC5tRkMgPSBtZWFuKGZjKSkKIyBmaW5hbGx5LCB3ZSBub3JtYWxpemUgdGhlIG5vbi13dCBzdHJhaW5zIGJ5IHRoZSB3aWxkIHR5cGUgbWVhbiBmb2xkIGNoYW5nZSBhdCBlYWNoIHRpbWUgcG9pbnQKcGkuZGF0MSA8LSBwaS5kYXQxICU+JSAKICBsZWZ0X2pvaW4ocGkud3QuZmMsIGJ5ID0gInRpbWUiKSAlPiUgCiAgbXV0YXRlKG5vcm1GQyA9IGZjIC8gd3QubUZDKQpgYGAKcGxvdCB0aGUgbm9ybWFsaXplZCBmb2xkIGNoYW5nZXMKYGBge3J9CnBpLmRhdDEgJT4lIAogIGdncGxvdChhZXMoeCA9IHRpbWUsIHkgPSBub3JtRkMsIGNvbG9yID0gZ2Vub3R5cGUpKSArIGdlb21fcG9pbnQoc2l6ZSA9IDAuMikgKyAKICBzdGF0X3N1bW1hcnkoZnVuID0gIm1lYW4iLCBnZW9tID0gInBvaW50Iiwgc2l6ZSA9IDIpICsKICBzdGF0X3Ntb290aChhZXMoeCA9IGFzLm51bWVyaWModGltZSkpLCBzZSA9IEZBTFNFKSArCiAgeWxhYigiZm9sZCBjaGFuZ2UgcmVsYXRpdmUgdG8gMCBtaW4sIG5vcm1hbGl6ZWQgdG8gd2lsZCB0eXBlIikgKwogIHRoZW1lX2J3KCkKYGBgCldlIGNvdWxkIHBlcmZvcm0gbGluZWFyIHJlZ3Jlc3Npb24gb24gdGhlIGRhdGEgdG8gdGVzdCBpZiB0aGUgc2xvcGUgaXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB6ZXJvLiBXZSB1c2UgYSAibmVzdC1tYXAtdW5uZXN0IiB3b3JrZmxvdyAoc2VlIHRoaXMgW2xpbmtdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9icm9vbS92aWduZXR0ZXMvYnJvb21fYW5kX2RwbHlyLmh0bWwpKQpgYGB7cn0KcGkuZGF0MSAlPiUgCiAgZmlsdGVyKGdlbm90eXBlICE9ICJ3dCIpICU+JSAKICBtdXRhdGUodGltZSA9IGFzLm51bWVyaWModGltZSkpICU+JSAKICBncm91cF9ieShnZW5vdHlwZSkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKAogICAgZml0ID0gbWFwKGRhdGEsIH4gbG0obm9ybUZDIH4gdGltZSwgZGF0YSA9IC54KSksCiAgICB0aWRpZWQgPSBtYXAoZml0LCB0aWR5KQogICkgJT4lIAogIHVubmVzdCh0aWRpZWQpCiAgCmBgYAoKRm9yIGVhY2ggbm9uLXd0IGdlbm90eXBlLCB3ZSBjYW4gcmVhZCB0aGUgZXN0aW1hdGVzIG9mIHRoZSBpbnRlcmNlcHQgYW5kIHNsb3BlICh0aW1lKSBhbmQgdGhlIHNpZ25pZmljYW5jZSBvZiB0aGVtLiBXZSBzZWUgdGhhdCBfbXNuMuKIhl8gaGFzIGEgc2xvcGUgdGhhdCBpcyBub3Qgc2lnaW5pZmljYW50bHkgZGlmZmVyZW50IGZyb20gemVybyB3aGlsZSBib3RoIF9tc2404oiGXyBhbmQgX21zbjLiiIYgbXNuNOKIhl8gc2hvdyBzaWduaWZpY2FudCBzbG9wZXMgdGhhdCBhcmUgYmVsb3cgemVybywgaW5kaWNhdGluZyB0aGF0IHRoZXkgYm90aCBzaG93IGEgbGVzcyBlZmZlY3RpdmUgaW5kdWN0aW9uIG9mIF9DVEExXyBjb21wYXJlZCB3aXRoIHRoZSB3aWxkIHR5cGUuIFRoaXMgYWxsb3dzIHVzIHRvIGNvbmNsdWRlIHRoYXQgbW9zdCBsaWtlbHkgTXNuNCBpcyBhIHBvc2l0aXZlIHJlZ3VsYXRvciBvZiBfQ1RBMV8gaW4gX0MuIGdsYWJyYXRhXw==