What you see here is an R notebook. Unless you’ve been looking ahead, you will have seen this in class on Tuesday when I introduce the lab exercise. Nick will talk about it more in lab. Let’s start with a simple example that illustrates how R notebooks work. As you’ll see, they allow us to intersperse text (like this) with R code that we execute (as you’ll see below). We’ll use the data from Isotoma petraea that we discussed in class to illustrate hierfstat.

Converting the Isotoma data to a different format

hierfstat needs the data in a different format from what is available on the website. This piece of code reads in the data directly from the website and converts it to the format that hierfstat uses. Other than the cute trick of reading the CSV file directly from the server rather than downloading it first, you can ignore all of the other coding.[^If you’re interested, you’re welcome to read it and see if you can figure out what it does. If you try and get stuck, feel free to ask me. I’m not asking you to spend any time on understanding this, because you are very unlikely to encounter genetic data in a format like the Isotoma petraea data any where else.]

## The options line turns off the messages that tidyverse usually prints when
## it loads.
##
options(tidyverse.quiet = TRUE) 
library("tidyverse")

## The following line clears out any objects in memory. I make it a habit to do this so that I can make sure
## that things left over from the last time I ran R don't confuse things.
##
rm(list = ls())

dat <- read_csv("http://darwin.eeb.uconn.edu/eeb348-resources/isotoma.csv",
                col_types = cols(pop = col_character(), .default = col_integer()))

## If you know R, you'll recognize that I could have expressed this much more 
## succintly, but for anyone who cares to follow the logic, this version should 
## be easier to follow.
##
for (i in 1:nrow(dat)) {
  for (j in 2:ncol(dat)) {
    if (!is.na(dat[i, j])) {
      if (dat[i, j] == 0) {
        dat[i, j] <- 11
      } else if (dat[i, j] == 1) {
        dat[i, j] <- 12
      } else if (dat[i, j] == 2) {
        dat[i, j] <- 22
      }
    }   
  }
}
## This line converts the population abbreviatons to numbers
##
dat$Location <- as.numeric(as.factor(dat$pop))
## The first line puts Location in the first column. The second drops the pop column.
##
dat <- relocate(dat, Location) %>%
  select(-pop)
dat <- as.data.frame(dat)

Using hierfstat

We use wc() to estimate Weir and Cockerham’s \(F\)-statistics.1

library(hierfstat)

dat_fst <- wc(dat, diploid = TRUE)
dat_fst
$FST
[1] 0.03869543

$FIS
[1] 0.539859

That’s all there is to it. You don’t need to include the diploid = TRUE, but it’s good form to do so. If you happened to try this with the original file you downloaded, you’d get an error because the data aren’t in the right format. The numbers above match what I mentioned in lecture (with a small rounding error in the 4th decimal place for \(F_{IS}\))

You can get a sense of how reliable those point estimates are by bootstrapping the estimates using boot.vc(). The first argument to boot.vc() is the list of populations from which each individual was collected (as a number, not as characters). The second argument to boot.vc() is the matrix of genotypes at all of the loci. Our data frame dat contains the population numbers in the first column, and the genotype information in the remaining column. We can select the first column as dat[, 1]. We can select all of the columns except the first column as dat[, -1].

boot.vc(dat[, 1], dat[, -1], diploid = TRUE)$ci
Error in if (nloc < 5) { : argument is of length zero

Bootstrapping didn’t work in this case, because it requires a minimum of 5 loci.[^If you’ve never encountered bootstrapping before, and you want to know how it works, feel free to ask. If you already know about bootstrapping, it might help you to know that we are bootstrapping loci rather than individuals.]

Lab exercise

We are going to use a subset of the data that Rachel Prunier and collaborators (including me) used to analyze the genetic structure of Protea repens https://doi.org/10.3732/ajb.1600232. You’ll find the data on the course website at http://darwin.eeb.uconn.edu/eeb348-resources/repens-outliers.csv and at http://darwin.eeb.uconn.edu/eeb348-resources/repens-outliers.stru.2

  1. Download the data in the .stru file. Then work through the following steps to analyze the data with wc().3

  2. Convert the data to a form that hierfstat can use by running read.structure() from adegenet.4. Note: There are 662 genotypes (individuals), 173 markers (loci), column 1 contains the labels for genotypes (individuals), column 2 contains the population factor (the population/locality from which a particular sample was collected), there are no optional columns, row 1 contains the marker (locus) names, and genotypes are coded in two rows. If everything worked properly, you’ll see the following message:

     Converting data from a STRUCTURE .stru file to a genind object... 
     
  3. Now use wc() to produce estimates of \(F_{IS}\) and \(F_{ST}\).

  4. Now convert the genind object that you used with wc() to a hierfstat data frame (using genind2hierfstat()), and use that dataframe to construct 95 percent confidence intervals for \(F_{IS}\) and \(F_{ST}\)

     boot.vc(repens_df[, 1], repens_df[, -1], diploid = TRUE)$ci
     

    repens_df is the name of the data frame I used. The first argument selects only the pop column (the one with the populations), and the second excludes the pop column, leaving a data frame with only the genotype data.

  5. Is there evidence of inbreeding within populations?

  6. Is there evidence of genetic differentiation among populations?

Feel free simply to embed the R code in a copy of this notebook if you’re so inclined. but if you do, be sure to state explicitly how to interpret the output.[^Nick and I know how to do it, of course, but I want to make sure you know how to do it too.]


  1. You can probably guess why the function is called wc().↩︎

  2. I’ll explain what the .stru extension refers to next week.↩︎

  3. You can also use the trick of simply using the URL above to read the data directly from the course website if you’d prefer.↩︎

  4. You’ll need to use install.packages() to install adegenet↩︎

LS0tCnRpdGxlOiAiJEYkLXN0YXRpc3RpY3Mgd2l0aCBgaGllcmZzdGF0YCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKV2hhdCB5b3Ugc2VlIGhlcmUgaXMgYW4gYFJgIG5vdGVib29rLiBVbmxlc3MgeW91J3ZlIGJlZW4gbG9va2luZyBhaGVhZCwgeW91IHdpbGwgaGF2ZSBzZWVuIHRoaXMgaW4gY2xhc3Mgb24gVHVlc2RheSB3aGVuIEkgaW50cm9kdWNlIHRoZSBsYWIgZXhlcmNpc2UuIE5pY2sgd2lsbCB0YWxrIGFib3V0IGl0IG1vcmUgaW4gbGFiLiBMZXQncyBzdGFydCB3aXRoIGEgc2ltcGxlIGV4YW1wbGUgdGhhdCBpbGx1c3RyYXRlcyBob3cgYFJgIG5vdGVib29rcyB3b3JrLiBBcyB5b3UnbGwgc2VlLCB0aGV5IGFsbG93IHVzIHRvIGludGVyc3BlcnNlIHRleHQgKGxpa2UgdGhpcykgd2l0aCBgUmAgY29kZSB0aGF0IHdlIGV4ZWN1dGUgKGFzIHlvdSdsbCBzZWUgYmVsb3cpLiBXZSdsbCB1c2UgdGhlIGRhdGEgZnJvbSAqSXNvdG9tYSBwZXRyYWVhKiB0aGF0IHdlIGRpc2N1c3NlZCBpbiBjbGFzcyB0byBpbGx1c3RyYXRlIGBoaWVyZnN0YXRgLiAKCiMjIENvbnZlcnRpbmcgdGhlICpJc290b21hKiBkYXRhIHRvIGEgZGlmZmVyZW50IGZvcm1hdAoKYGhpZXJmc3RhdGAgbmVlZHMgdGhlIGRhdGEgaW4gYSBkaWZmZXJlbnQgZm9ybWF0IGZyb20gd2hhdCBpcyBhdmFpbGFibGUgb24gdGhlIHdlYnNpdGUuIFRoaXMgcGllY2Ugb2YgY29kZSByZWFkcyBpbiB0aGUgZGF0YSBkaXJlY3RseSBmcm9tIHRoZSB3ZWJzaXRlIGFuZCBjb252ZXJ0cyBpdCB0byB0aGUgZm9ybWF0IHRoYXQgYGhpZXJmc3RhdGAgdXNlcy4gT3RoZXIgdGhhbiB0aGUgY3V0ZSB0cmljayBvZiByZWFkaW5nIHRoZSBDU1YgZmlsZSBkaXJlY3RseSBmcm9tIHRoZSBzZXJ2ZXIgcmF0aGVyIHRoYW4gZG93bmxvYWRpbmcgaXQgZmlyc3QsIHlvdSBjYW4gaWdub3JlIGFsbCBvZiB0aGUgb3RoZXIgY29kaW5nLlteSWYgeW91J3JlIGludGVyZXN0ZWQsIHlvdSdyZSB3ZWxjb21lIHRvIHJlYWQgaXQgYW5kIHNlZSBpZiB5b3UgY2FuIGZpZ3VyZSBvdXQgd2hhdCBpdCBkb2VzLiBJZiB5b3UgdHJ5IGFuZCBnZXQgc3R1Y2ssIGZlZWwgZnJlZSB0byBhc2sgbWUuIEknbSBub3QgYXNraW5nIHlvdSB0byBzcGVuZCBhbnkgdGltZSBvbiB1bmRlcnN0YW5kaW5nIHRoaXMsIGJlY2F1c2UgeW91IGFyZSB2ZXJ5IHVubGlrZWx5IHRvIGVuY291bnRlciBnZW5ldGljIGRhdGEgaW4gYSBmb3JtYXQgbGlrZSB0aGUgKklzb3RvbWEgcGV0cmFlYSogZGF0YSBhbnkgd2hlcmUgZWxzZS5dCgpgYGB7cn0KIyMgVGhlIG9wdGlvbnMgbGluZSB0dXJucyBvZmYgdGhlIG1lc3NhZ2VzIHRoYXQgdGlkeXZlcnNlIHVzdWFsbHkgcHJpbnRzIHdoZW4KIyMgaXQgbG9hZHMuCiMjCm9wdGlvbnModGlkeXZlcnNlLnF1aWV0ID0gVFJVRSkgCmxpYnJhcnkoInRpZHl2ZXJzZSIpCgojIyBUaGUgZm9sbG93aW5nIGxpbmUgY2xlYXJzIG91dCBhbnkgb2JqZWN0cyBpbiBtZW1vcnkuIEkgbWFrZSBpdCBhIGhhYml0IHRvIGRvIHRoaXMgc28gdGhhdCBJIGNhbiBtYWtlIHN1cmUKIyMgdGhhdCB0aGluZ3MgbGVmdCBvdmVyIGZyb20gdGhlIGxhc3QgdGltZSBJIHJhbiBSIGRvbid0IGNvbmZ1c2UgdGhpbmdzLgojIwpybShsaXN0ID0gbHMoKSkKCmRhdCA8LSByZWFkX2NzdigiaHR0cDovL2Rhcndpbi5lZWIudWNvbm4uZWR1L2VlYjM0OC1yZXNvdXJjZXMvaXNvdG9tYS5jc3YiLAogICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyhwb3AgPSBjb2xfY2hhcmFjdGVyKCksIC5kZWZhdWx0ID0gY29sX2ludGVnZXIoKSkpCgojIyBJZiB5b3Uga25vdyBSLCB5b3UnbGwgcmVjb2duaXplIHRoYXQgSSBjb3VsZCBoYXZlIGV4cHJlc3NlZCB0aGlzIG11Y2ggbW9yZSAKIyMgc3VjY2luY3RseSwgYnV0IGZvciBhbnlvbmUgd2hvIGNhcmVzIHRvIGZvbGxvdyB0aGUgbG9naWMsIHRoaXMgdmVyc2lvbiBzaG91bGQgCiMjIGJlIGVhc2llciB0byBmb2xsb3cuCiMjCmZvciAoaSBpbiAxOm5yb3coZGF0KSkgewogIGZvciAoaiBpbiAyOm5jb2woZGF0KSkgewogICAgaWYgKCFpcy5uYShkYXRbaSwgal0pKSB7CiAgICAgIGlmIChkYXRbaSwgal0gPT0gMCkgewogICAgICAgIGRhdFtpLCBqXSA8LSAxMQogICAgICB9IGVsc2UgaWYgKGRhdFtpLCBqXSA9PSAxKSB7CiAgICAgICAgZGF0W2ksIGpdIDwtIDEyCiAgICAgIH0gZWxzZSBpZiAoZGF0W2ksIGpdID09IDIpIHsKICAgICAgICBkYXRbaSwgal0gPC0gMjIKICAgICAgfQogICAgfSAgIAogIH0KfQojIyBUaGlzIGxpbmUgY29udmVydHMgdGhlIHBvcHVsYXRpb24gYWJicmV2aWF0aW9ucyB0byBudW1iZXJzCiMjCmRhdCRMb2NhdGlvbiA8LSBhcy5udW1lcmljKGFzLmZhY3RvcihkYXQkcG9wKSkKIyMgVGhlIGZpcnN0IGxpbmUgcHV0cyBMb2NhdGlvbiBpbiB0aGUgZmlyc3QgY29sdW1uLiBUaGUgc2Vjb25kIGRyb3BzIHRoZSBwb3AgY29sdW1uLgojIwpkYXQgPC0gcmVsb2NhdGUoZGF0LCBMb2NhdGlvbikgJT4lCiAgc2VsZWN0KC1wb3ApCmRhdCA8LSBhcy5kYXRhLmZyYW1lKGRhdCkKYGBgCgojIyBVc2luZyBgaGllcmZzdGF0YAoKV2UgdXNlIGB3YygpYCB0byBlc3RpbWF0ZSBXZWlyIGFuZCBDb2NrZXJoYW0ncyAkRiQtc3RhdGlzdGljcy5eW1lvdSBjYW4gcHJvYmFibHkgZ3Vlc3Mgd2h5IHRoZSBmdW5jdGlvbiBpcyBjYWxsZWQgYHdjKClgLl0KCmBgYHtyfQpsaWJyYXJ5KGhpZXJmc3RhdCkKCmRhdF9mc3QgPC0gd2MoZGF0LCBkaXBsb2lkID0gVFJVRSkKZGF0X2ZzdApgYGAKClRoYXQncyBhbGwgdGhlcmUgaXMgdG8gaXQuIFlvdSBkb24ndCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBkaXBsb2lkID0gVFJVRWAsIGJ1dCBpdCdzIGdvb2QgZm9ybSB0byBkbyBzby4gSWYgeW91IGhhcHBlbmVkIHRvIHRyeSB0aGlzIHdpdGggdGhlIG9yaWdpbmFsIGZpbGUgeW91IGRvd25sb2FkZWQsIHlvdSdkIGdldCBhbiBlcnJvciBiZWNhdXNlIHRoZSBkYXRhIGFyZW4ndCBpbiB0aGUgcmlnaHQgZm9ybWF0LiBUaGUgbnVtYmVycyBhYm92ZSBtYXRjaCB3aGF0IEkgbWVudGlvbmVkIGluIGxlY3R1cmUgKHdpdGggYSBzbWFsbCByb3VuZGluZyBlcnJvciBpbiB0aGUgNHRoIGRlY2ltYWwgcGxhY2UgZm9yICRGX3tJU30kKQoKWW91IGNhbiBnZXQgYSBzZW5zZSBvZiBob3cgcmVsaWFibGUgdGhvc2UgcG9pbnQgZXN0aW1hdGVzIGFyZSBieSBib290c3RyYXBwaW5nIHRoZSBlc3RpbWF0ZXMgdXNpbmcgYGJvb3QudmMoKWAuIFRoZSBmaXJzdCBhcmd1bWVudCB0byBgYm9vdC52YygpYCBpcyB0aGUgbGlzdCBvZiBwb3B1bGF0aW9ucyBmcm9tIHdoaWNoIGVhY2ggaW5kaXZpZHVhbCB3YXMgY29sbGVjdGVkIChhcyBhIG51bWJlciwgbm90IGFzIGNoYXJhY3RlcnMpLiBUaGUgc2Vjb25kIGFyZ3VtZW50IHRvIGBib290LnZjKClgIGlzIHRoZSBtYXRyaXggb2YgZ2Vub3R5cGVzIGF0IGFsbCBvZiB0aGUgbG9jaS4gT3VyIGRhdGEgZnJhbWUgYGRhdGAgY29udGFpbnMgdGhlIHBvcHVsYXRpb24gbnVtYmVycyBpbiB0aGUgZmlyc3QgY29sdW1uLCBhbmQgdGhlIGdlbm90eXBlIGluZm9ybWF0aW9uIGluIHRoZSByZW1haW5pbmcgY29sdW1uLiBXZSBjYW4gc2VsZWN0IHRoZSBmaXJzdCBjb2x1bW4gYXMgYGRhdFssIDFdYC4gV2UgY2FuIHNlbGVjdCBhbGwgb2YgdGhlIGNvbHVtbnMgKmV4Y2VwdCogdGhlIGZpcnN0IGNvbHVtbiBhcyBgZGF0WywgLTFdYC4gCgpgYGB7cn0KYm9vdC52YyhkYXRbLCAxXSwgZGF0WywgLTFdLCBkaXBsb2lkID0gVFJVRSkkY2kKYGBgCkJvb3RzdHJhcHBpbmcgZGlkbid0IHdvcmsgaW4gdGhpcyBjYXNlLCBiZWNhdXNlIGl0IHJlcXVpcmVzIGEgbWluaW11bSBvZiA1IGxvY2kuW15JZiB5b3UndmUgbmV2ZXIgZW5jb3VudGVyZWQgYm9vdHN0cmFwcGluZyBiZWZvcmUsIGFuZCB5b3Ugd2FudCB0byBrbm93IGhvdyBpdCB3b3JrcywgZmVlbCBmcmVlIHRvIGFzay4gSWYgeW91IGFscmVhZHkga25vdyBhYm91dCBib290c3RyYXBwaW5nLCBpdCBtaWdodCBoZWxwIHlvdSB0byBrbm93IHRoYXQgd2UgYXJlIGJvb3RzdHJhcHBpbmcgbG9jaSByYXRoZXIgdGhhbiBpbmRpdmlkdWFscy5dIAoKIyMgTGFiIGV4ZXJjaXNlCgpXZSBhcmUgZ29pbmcgdG8gdXNlIGEgc3Vic2V0IG9mIHRoZSBkYXRhIHRoYXQgUmFjaGVsIFBydW5pZXIgYW5kIGNvbGxhYm9yYXRvcnMgKGluY2x1ZGluZyBtZSkgdXNlZCB0byBhbmFseXplIHRoZSBnZW5ldGljIHN0cnVjdHVyZSBvZiAqUHJvdGVhIHJlcGVucyogW2h0dHBzOi8vZG9pLm9yZy8xMC4zNzMyL2FqYi4xNjAwMjMyXShodHRwczovL2RvaS5vcmcvMTAuMzczMi9hamIuMTYwMDIzMikuIFlvdSdsbCBmaW5kIHRoZSBkYXRhIG9uIHRoZSBjb3Vyc2Ugd2Vic2l0ZSBhdCBbaHR0cDovL2Rhcndpbi5lZWIudWNvbm4uZWR1L2VlYjM0OC1yZXNvdXJjZXMvcmVwZW5zLW91dGxpZXJzLmNzdl0oaHR0cDovL2Rhcndpbi5lZWIudWNvbm4uZWR1L2VlYjM0OC1yZXNvdXJjZXMvcmVwZW5zLW91dGxpZXJzLmNzdikgYW5kIGF0IFtodHRwOi8vZGFyd2luLmVlYi51Y29ubi5lZHUvZWViMzQ4LXJlc291cmNlcy9yZXBlbnMtb3V0bGllcnMuc3RydV0oaHR0cDovL2Rhcndpbi5lZWIudWNvbm4uZWR1L2VlYjM0OC1yZXNvdXJjZXMvcmVwZW5zLW91dGxpZXJzLnN0cnUpLl5bSSdsbCBleHBsYWluIHdoYXQgdGhlIGAuc3RydWAgZXh0ZW5zaW9uIHJlZmVycyB0byBuZXh0IHdlZWsuXQoKMS4gRG93bmxvYWQgdGhlIGRhdGEgaW4gdGhlIGAuc3RydWAgZmlsZS4gVGhlbiB3b3JrIHRocm91Z2ggdGhlIGZvbGxvd2luZyBzdGVwcyB0byBhbmFseXplIHRoZSBkYXRhIHdpdGggYHdjKClgLl5bWW91IGNhbiBhbHNvIHVzZSB0aGUgdHJpY2sgb2Ygc2ltcGx5IHVzaW5nIHRoZSBVUkwgYWJvdmUgdG8gcmVhZCB0aGUgZGF0YSBkaXJlY3RseSBmcm9tIHRoZSBjb3Vyc2Ugd2Vic2l0ZSBpZiB5b3UnZCBwcmVmZXIuXQoKMi4gQ29udmVydCB0aGUgZGF0YSB0byBhIGZvcm0gdGhhdCBgaGllcmZzdGF0YCBjYW4gdXNlIGJ5IHJ1bm5pbmcgYHJlYWQuc3RydWN0dXJlKClgIGZyb20gYGFkZWdlbmV0YC5eW1lvdSdsbCBuZWVkIHRvIHVzZSBgaW5zdGFsbC5wYWNrYWdlcygpYCB0byBpbnN0YWxsIGBhZGVnZW5ldGBdLiBOb3RlOiBUaGVyZSBhcmUgNjYyIGdlbm90eXBlcyAoaW5kaXZpZHVhbHMpLCAxNzMgbWFya2VycyAobG9jaSksIGNvbHVtbiAxIGNvbnRhaW5zIHRoZSBsYWJlbHMgZm9yIGdlbm90eXBlcyAoaW5kaXZpZHVhbHMpLCBjb2x1bW4gMiBjb250YWlucyB0aGUgcG9wdWxhdGlvbiBmYWN0b3IgKHRoZSBwb3B1bGF0aW9uL2xvY2FsaXR5IGZyb20gd2hpY2ggYSBwYXJ0aWN1bGFyIHNhbXBsZSB3YXMgY29sbGVjdGVkKSwgdGhlcmUgYXJlIG5vIG9wdGlvbmFsIGNvbHVtbnMsIHJvdyAxIGNvbnRhaW5zIHRoZSBtYXJrZXIgKGxvY3VzKSBuYW1lcywgYW5kIGdlbm90eXBlcyBhcmUgY29kZWQgaW4gdHdvIHJvd3MuIElmIGV2ZXJ5dGhpbmcgd29ya2VkIHByb3Blcmx5LCB5b3UnbGwgc2VlIHRoZSBmb2xsb3dpbmcgbWVzc2FnZToKICAgIAogICAgPHByZT4KIENvbnZlcnRpbmcgZGF0YSBmcm9tIGEgU1RSVUNUVVJFIC5zdHJ1IGZpbGUgdG8gYSBnZW5pbmQgb2JqZWN0Li4uIAogICAgPC9wcmU+CiAgICAKMy4gTm93IHVzZSBgd2MoKWAgdG8gcHJvZHVjZSBlc3RpbWF0ZXMgb2YgJEZfe0lTfSQgYW5kICRGX3tTVH0kLgogICAgCjQuIE5vdyBjb252ZXJ0IHRoZSBgZ2VuaW5kYCBvYmplY3QgdGhhdCB5b3UgdXNlZCB3aXRoIGB3YygpYCB0byBhIGBoaWVyZnN0YXRgIGRhdGEgZnJhbWUgKHVzaW5nIGBnZW5pbmQyaGllcmZzdGF0KClgKSwgYW5kIHVzZSB0aGF0IGRhdGFmcmFtZSB0byBjb25zdHJ1Y3QgOTUgcGVyY2VudCBjb25maWRlbmNlIGludGVydmFscyBmb3IgJEZfe0lTfSQgYW5kICRGX3tTVH0kCiAgICAKICAgIDxwcmU+CiAgICBib290LnZjKHJlcGVuc19kZlssIDFdLCByZXBlbnNfZGZbLCAtMV0sIGRpcGxvaWQgPSBUUlVFKSRjaQogICAgPC9wcmU+CiAgICAKICAgIGByZXBlbnNfZGZgIGlzIHRoZSBuYW1lIG9mIHRoZSBkYXRhIGZyYW1lIEkgdXNlZC4gVGhlIGZpcnN0IGFyZ3VtZW50IHNlbGVjdHMgb25seSB0aGUgYHBvcGAgY29sdW1uICh0aGUgb25lIHdpdGggdGhlIHBvcHVsYXRpb25zKSwgYW5kIHRoZSBzZWNvbmQgZXhjbHVkZXMgdGhlIGBwb3BgIGNvbHVtbiwgbGVhdmluZyBhIGRhdGEgZnJhbWUgd2l0aCBvbmx5IHRoZSBnZW5vdHlwZSBkYXRhLiAKICAgIAo1LiBJcyB0aGVyZSBldmlkZW5jZSBvZiBpbmJyZWVkaW5nIHdpdGhpbiBwb3B1bGF0aW9ucz8gCgo2LiBJcyB0aGVyZSBldmlkZW5jZSBvZiBnZW5ldGljIGRpZmZlcmVudGlhdGlvbiBhbW9uZyBwb3B1bGF0aW9ucz8KCkZlZWwgZnJlZSBzaW1wbHkgdG8gZW1iZWQgdGhlIGBSYCBjb2RlIGluIGEgY29weSBvZiB0aGlzIG5vdGVib29rIGlmIHlvdSdyZSBzbyBpbmNsaW5lZC4gKioqYnV0KioqIGlmIHlvdSBkbywgYmUgc3VyZSB0byBzdGF0ZSBleHBsaWNpdGx5IGhvdyB0byBpbnRlcnByZXQgdGhlIG91dHB1dC5bXk5pY2sgYW5kIEkga25vdyBob3cgdG8gZG8gaXQsIG9mIGNvdXJzZSwgYnV0IEkgd2FudCB0byBtYWtlIHN1cmUgeW91IGtub3cgaG93IHRvIGRvIGl0IHRvby5dIA==