Overview

Two weeks ago we explored properties of the coalescent, focusing on how population structure affected the time to coalescence. This week we’re going to use ms() again, but instead of exploring properties of the coalescent in isolation, we’ll compare expected times to coalescence with “observed” times to coalescence. We can’t really observe coalescence times, but we can estimate them from nucleotide sequence data. If the sequences are evolving neutrally, the coalescence times we estimate should match those we expect pretty closely.

An example from Drosophila

I downloaded 24 sequences of alcohol dehydrogenase (ADH) from Drosophila melanogaster from Genbank, and I aligned them using Muscle. I eliminated duplicate sequences, leaving 9 sequences in the data set. I converted the ClustalW alignments to NEXUS format, and analyzed their relationships in Mr. Bayes, assuming a strict molecular clock.1 Here’s what the results look like.

library(ape)
library(phyclust)
library(ggplot2)

adh_bayes <- read.nexus("Drosophila-ADH.clock.con.tre")
plot(adh_bayes)
nodelabels()

branching.times() gives us the time each branching event occurred, where the integers in the list below correspond to the numbers in the tree above.

branching.times(adh_bayes)
         10          11          12          13          14 
0.018170630 0.001028510 0.005755670 0.003281008 0.001262989 
         15          16          17 
0.000273063 0.004166878 0.002542797 

Notice that the times aren’t in order. The same is true for the output of ms().

ms_out <- ms(nsam = 10, opts = "-T")
ms_tree <- read.tree(text = ms_out)
branching.times(ms_tree)
         11          12          13          14          15 
0.584692901 0.163602656 0.070539040 0.002071878 0.049311867 
         16          17          18          19 
0.049023239 0.189547693 0.024402907 0.014947687 

This didn’t affect us earlier, because we were only looking at the deepest node, and the deepest node is always the first one in the list. But to compare branching times across the entire tree, we have to sort them. In addition the deepest node is scaled in coalescent units in the output from ms() and in number of substitutions in the estimates. To make them comparable, we also have to “normalize” them by expressing them as a fraction of the time to the deepest node. The following function produces a series of coalescent samples and compares the coalescent times at each node that are observed with those that are expected. It returns the result as a data frame.2

compare_coalescent <- function(tree, n_reps = 1000) {
  n_taxa <- length(tree$tip.label)
  coal_times <- matrix(nrow = n_reps, ncol = n_taxa - 1)
  for (i in 1:n_reps) {
    ms_out <- ms(nsam = n_taxa, opts = "-T")
    ms_tree <- read.tree(text = ms_out)
    coal_times[i, ] <- branching.times(ms_tree)
    coal_times[i, ] <- sort(coal_times[i, ], decreasing = TRUE)
    for (j in 1:(n_taxa - 1)) {
      coal_times[i, j] <- coal_times[i, j]/coal_times[i, 1]
    }
  }
  max_time <- max(branching.times(tree))
  observed <- sort(branching.times(tree), decreasing = TRUE)
  observed <- observed/max_time
  result <- data.frame(Observed = observed,
                       Expected = apply(coal_times, 2, mean),
                       Lower_2.5 = apply(coal_times, 2, quantile, 0.025),
                       Upper_97.5 = apply(coal_times, 2, quantile, 0.975))
  return(result)
}

Now we can call it with our observed tree and examine the results. First, we’ll just look at the mean and 95 percent credible interval for each node.

result <- compare_coalescent(adh_bayes)
round(result, 3)

The Observed doesn’t look markedly different from the Expected, but it will probably be easier to see if we plot them against one another.3

p <- ggplot(result, aes(x = Expected, y = Observed)) +
  geom_point() +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", 
              color = "red") +
  theme_bw()
p

That doesn’t look to bad, but it’s only showing the mean of the simulations. It’s not showing anything about the range of plausible values. Let’s add that to the plot and see what it looks like.

p <- ggplot(result, aes(x = Expected, y = Observed)) +
  geom_point() +
  geom_errorbar(aes(xmin = Lower_2.5, xmax = Upper_97.5, width = 0.02)) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", 
              color = "red") +
  theme_bw()
p

So it appears for these data there’s a reasonably good fit between Observed and Expected. There certainly isn’t a consistent pattern of mismatch.

Lab 9

I’ve mentioned self-incompatibility alleles several times in lecture. In this week’s exercise we’re going to explore sequence variation in a sample of them. More precisely, I’m going to provide you with a tree describing relationships among self-incompatibility alleles in Solanum, the genus that includes potatoes, tomatoes, and eggplants. The data are derived from Richman and Kohn.4 The original data set included 67 nucleotide sequences. After aligning the sequences with Muscle and eliminating a few duplicates, 63 remain. I estimated a phylogenetic tree of relationships with with Mr. Bayes assuming a strict molecular clock,5 and you’ll find the resulting consensus tree at http://darwin.eeb.uconn.edu/eeb348-resources/sRNase.clock.con.tre.6

Using this tree, explore the relationship between observed coalescence times, i.e., the estimated branching times in the output from Mr. Bayes, with those expected, i.e., the branching times simulated by ms(). The compare_coalescent() function above and the code following it that shows how to look at the numbers and how to visualize the results should make that pretty easy. Once you’ve done that, answer these two questions:

  1. What systematic differences between observed and expected coalescence times do you see?

  2. Given what I’ve said about self-incompatibility in lecture and what Richman and Kohn say about it in their paper, how would you explain the discrepancies that you see.


  1. prset = brlenspr=clock:uniform with a GTR+I+\(\Gamma\) substitution model for any of you who care.↩︎

  2. If you call it withough specifying the number of replications, it will default to 1000. One thousand replications should be plenty, and it runs pretty fast (4-5 seconds on my laptop), but feel free to play around with different choices if you’re so inclined.↩︎

  3. The dashed red line is the 1:1 line on which all of the points would lie if Observed exactly matched Expected.↩︎

  4. Richman, A.D., and J.R. Kohn. 2000. Evolutionary genetics of self-incompatibility in the Solanaceae. Plant Molecular Biology 42:169-179. doi: 10.1023/A:1006336206637↩︎

  5. I used the same parameters as with the ADH example above.↩︎

  6. Note: You can either download the file to your hard drive, or you can read it directly with read.nexus(), putting in the full URL (in quotes) instead of the filename.↩︎

LS0tCnRpdGxlOiAiQ29tcGFyaW5nIG9ic2VydmVkIGNvYWxlc2NlbmNlIHRpbWVzIHRvIGV4cGVjdGVkIGNvYWxlc2NlbmNlIHRpbWVzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKIyMgT3ZlcnZpZXcKClR3byB3ZWVrcyBhZ28gd2UgZXhwbG9yZWQgcHJvcGVydGllcyBvZiB0aGUgY29hbGVzY2VudCwgZm9jdXNpbmcgb24gaG93IHBvcHVsYXRpb24gc3RydWN0dXJlIGFmZmVjdGVkIHRoZSB0aW1lIHRvIGNvYWxlc2NlbmNlLiBUaGlzIHdlZWsgd2UncmUgZ29pbmcgdG8gdXNlIGBtcygpYCBhZ2FpbiwgYnV0IGluc3RlYWQgb2YgZXhwbG9yaW5nIHByb3BlcnRpZXMgb2YgdGhlIGNvYWxlc2NlbnQgaW4gaXNvbGF0aW9uLCB3ZSdsbCBjb21wYXJlIGV4cGVjdGVkIHRpbWVzIHRvIGNvYWxlc2NlbmNlIHdpdGggIm9ic2VydmVkIiB0aW1lcyB0byBjb2FsZXNjZW5jZS4gV2UgY2FuJ3QgcmVhbGx5IG9ic2VydmUgY29hbGVzY2VuY2UgdGltZXMsIGJ1dCB3ZSBjYW4gZXN0aW1hdGUgdGhlbSBmcm9tIG51Y2xlb3RpZGUgc2VxdWVuY2UgZGF0YS4gSWYgdGhlIHNlcXVlbmNlcyBhcmUgZXZvbHZpbmcgbmV1dHJhbGx5LCB0aGUgY29hbGVzY2VuY2UgdGltZXMgd2UgZXN0aW1hdGUgc2hvdWxkIG1hdGNoIHRob3NlIHdlIGV4cGVjdCBwcmV0dHkgY2xvc2VseS4KCiMjIyBBbiBleGFtcGxlIGZyb20gKkRyb3NvcGhpbGEqCgpJIGRvd25sb2FkZWQgMjQgc2VxdWVuY2VzIG9mIGFsY29ob2wgZGVoeWRyb2dlbmFzZSAoQURIKSBmcm9tICpEcm9zb3BoaWxhIG1lbGFub2dhc3RlciogZnJvbSBHZW5iYW5rLCBhbmQgSSBhbGlnbmVkIHRoZW0gdXNpbmcgW011c2NsZV0oaHR0cHM6Ly93d3cuZWJpLmFjLnVrL1Rvb2xzL3NlcnZpY2VzL3dlYl9tdXNjbGUvdG9vbGZvcm0uZWJpKS4gSSBlbGltaW5hdGVkIGR1cGxpY2F0ZSBzZXF1ZW5jZXMsIGxlYXZpbmcgOSBzZXF1ZW5jZXMgaW4gdGhlIGRhdGEgc2V0LiBJIGNvbnZlcnRlZCB0aGUgQ2x1c3RhbFcgYWxpZ25tZW50cyB0byBORVhVUyBmb3JtYXQsIGFuZCBhbmFseXplZCB0aGVpciByZWxhdGlvbnNoaXBzIGluIE1yLiBCYXllcywgYXNzdW1pbmcgYSBzdHJpY3QgbW9sZWN1bGFyIGNsb2NrLl5bYHByc2V0ID0gYnJsZW5zcHI9Y2xvY2s6dW5pZm9ybWAgd2l0aCBhIEdUUitJKyRcR2FtbWEkIHN1YnN0aXR1dGlvbiBtb2RlbCBmb3IgYW55IG9mIHlvdSB3aG8gY2FyZS5dIEhlcmUncyB3aGF0IHRoZSByZXN1bHRzIGxvb2sgbGlrZS4KCmBgYHtyfQpsaWJyYXJ5KGFwZSkKbGlicmFyeShwaHljbHVzdCkKbGlicmFyeShnZ3Bsb3QyKQoKYWRoX2JheWVzIDwtIHJlYWQubmV4dXMoIkRyb3NvcGhpbGEtQURILmNsb2NrLmNvbi50cmUiKQpwbG90KGFkaF9iYXllcykKbm9kZWxhYmVscygpCmBgYApgYnJhbmNoaW5nLnRpbWVzKClgIGdpdmVzIHVzIHRoZSB0aW1lIGVhY2ggYnJhbmNoaW5nIGV2ZW50IG9jY3VycmVkLCB3aGVyZSB0aGUgaW50ZWdlcnMgaW4gdGhlIGxpc3QgYmVsb3cgY29ycmVzcG9uZCB0byB0aGUgbnVtYmVycyBpbiB0aGUgdHJlZSBhYm92ZS4KCmBgYHtyfQpicmFuY2hpbmcudGltZXMoYWRoX2JheWVzKQpgYGAKCk5vdGljZSB0aGF0IHRoZSB0aW1lcyBhcmVuJ3QgaW4gb3JkZXIuIFRoZSBzYW1lIGlzIHRydWUgZm9yIHRoZSBvdXRwdXQgb2YgYG1zKClgLgpgYGB7cn0KbXNfb3V0IDwtIG1zKG5zYW0gPSAxMCwgb3B0cyA9ICItVCIpCm1zX3RyZWUgPC0gcmVhZC50cmVlKHRleHQgPSBtc19vdXQpCmJyYW5jaGluZy50aW1lcyhtc190cmVlKQpgYGAKClRoaXMgZGlkbid0IGFmZmVjdCB1cyBlYXJsaWVyLCBiZWNhdXNlIHdlIHdlcmUgb25seSBsb29raW5nIGF0IHRoZSBkZWVwZXN0IG5vZGUsIGFuZCB0aGUgZGVlcGVzdCBub2RlIGlzIGFsd2F5cyB0aGUgZmlyc3Qgb25lIGluIHRoZSBsaXN0LiBCdXQgdG8gY29tcGFyZSBicmFuY2hpbmcgdGltZXMgYWNyb3NzIHRoZSBlbnRpcmUgdHJlZSwgd2UgaGF2ZSB0byBzb3J0IHRoZW0uIEluIGFkZGl0aW9uIHRoZSBkZWVwZXN0IG5vZGUgaXMgc2NhbGVkIGluIGNvYWxlc2NlbnQgdW5pdHMgaW4gdGhlIG91dHB1dCBmcm9tIGBtcygpYCBhbmQgaW4gbnVtYmVyIG9mIHN1YnN0aXR1dGlvbnMgaW4gdGhlIGVzdGltYXRlcy4gVG8gbWFrZSB0aGVtIGNvbXBhcmFibGUsIHdlIGFsc28gaGF2ZSB0byAibm9ybWFsaXplIiB0aGVtIGJ5IGV4cHJlc3NpbmcgdGhlbSBhcyBhIGZyYWN0aW9uIG9mIHRoZSB0aW1lIHRvIHRoZSBkZWVwZXN0IG5vZGUuIFRoZSBmb2xsb3dpbmcgZnVuY3Rpb24gcHJvZHVjZXMgYSBzZXJpZXMgb2YgY29hbGVzY2VudCBzYW1wbGVzIGFuZCBjb21wYXJlcyB0aGUgY29hbGVzY2VudCB0aW1lcyBhdCBlYWNoIG5vZGUgdGhhdCBhcmUgb2JzZXJ2ZWQgd2l0aCB0aG9zZSB0aGF0IGFyZSBleHBlY3RlZC4gSXQgcmV0dXJucyB0aGUgcmVzdWx0IGFzIGEgZGF0YSBmcmFtZS5eW0lmIHlvdSBjYWxsIGl0IHdpdGhvdWdoIHNwZWNpZnlpbmcgdGhlIG51bWJlciBvZiByZXBsaWNhdGlvbnMsIGl0IHdpbGwgZGVmYXVsdCB0byAxMDAwLiBPbmUgdGhvdXNhbmQgcmVwbGljYXRpb25zIHNob3VsZCBiZSBwbGVudHksIGFuZCBpdCBydW5zIHByZXR0eSBmYXN0ICg0LTUgc2Vjb25kcyBvbiBteSBsYXB0b3ApLCBidXQgZmVlbCBmcmVlIHRvIHBsYXkgYXJvdW5kIHdpdGggZGlmZmVyZW50IGNob2ljZXMgaWYgeW91J3JlIHNvIGluY2xpbmVkLl0gCgpgYGB7cn0KY29tcGFyZV9jb2FsZXNjZW50IDwtIGZ1bmN0aW9uKHRyZWUsIG5fcmVwcyA9IDEwMDApIHsKICBuX3RheGEgPC0gbGVuZ3RoKHRyZWUkdGlwLmxhYmVsKQogIGNvYWxfdGltZXMgPC0gbWF0cml4KG5yb3cgPSBuX3JlcHMsIG5jb2wgPSBuX3RheGEgLSAxKQogIGZvciAoaSBpbiAxOm5fcmVwcykgewogICAgbXNfb3V0IDwtIG1zKG5zYW0gPSBuX3RheGEsIG9wdHMgPSAiLVQiKQogICAgbXNfdHJlZSA8LSByZWFkLnRyZWUodGV4dCA9IG1zX291dCkKICAgIGNvYWxfdGltZXNbaSwgXSA8LSBicmFuY2hpbmcudGltZXMobXNfdHJlZSkKICAgIGNvYWxfdGltZXNbaSwgXSA8LSBzb3J0KGNvYWxfdGltZXNbaSwgXSwgZGVjcmVhc2luZyA9IFRSVUUpCiAgICBmb3IgKGogaW4gMToobl90YXhhIC0gMSkpIHsKICAgICAgY29hbF90aW1lc1tpLCBqXSA8LSBjb2FsX3RpbWVzW2ksIGpdL2NvYWxfdGltZXNbaSwgMV0KICAgIH0KICB9CiAgbWF4X3RpbWUgPC0gbWF4KGJyYW5jaGluZy50aW1lcyh0cmVlKSkKICBvYnNlcnZlZCA8LSBzb3J0KGJyYW5jaGluZy50aW1lcyh0cmVlKSwgZGVjcmVhc2luZyA9IFRSVUUpCiAgb2JzZXJ2ZWQgPC0gb2JzZXJ2ZWQvbWF4X3RpbWUKICByZXN1bHQgPC0gZGF0YS5mcmFtZShPYnNlcnZlZCA9IG9ic2VydmVkLAogICAgICAgICAgICAgICAgICAgICAgIEV4cGVjdGVkID0gYXBwbHkoY29hbF90aW1lcywgMiwgbWVhbiksCiAgICAgICAgICAgICAgICAgICAgICAgTG93ZXJfMi41ID0gYXBwbHkoY29hbF90aW1lcywgMiwgcXVhbnRpbGUsIDAuMDI1KSwKICAgICAgICAgICAgICAgICAgICAgICBVcHBlcl85Ny41ID0gYXBwbHkoY29hbF90aW1lcywgMiwgcXVhbnRpbGUsIDAuOTc1KSkKICByZXR1cm4ocmVzdWx0KQp9CmBgYAoKTm93IHdlIGNhbiBjYWxsIGl0IHdpdGggb3VyIG9ic2VydmVkIHRyZWUgYW5kIGV4YW1pbmUgdGhlIHJlc3VsdHMuIEZpcnN0LCB3ZSdsbCBqdXN0IGxvb2sgYXQgdGhlIG1lYW4gYW5kIDk1IHBlcmNlbnQgY3JlZGlibGUgaW50ZXJ2YWwgZm9yIGVhY2ggbm9kZS4KCmBgYHtyfQpyZXN1bHQgPC0gY29tcGFyZV9jb2FsZXNjZW50KGFkaF9iYXllcykKcm91bmQocmVzdWx0LCAzKQpgYGAKClRoZSBPYnNlcnZlZCBkb2Vzbid0IGxvb2sgbWFya2VkbHkgZGlmZmVyZW50IGZyb20gdGhlIEV4cGVjdGVkLCBidXQgaXQgd2lsbCBwcm9iYWJseSBiZSBlYXNpZXIgdG8gc2VlIGlmIHdlIHBsb3QgdGhlbSBhZ2FpbnN0IG9uZSBhbm90aGVyLl5bVGhlIGRhc2hlZCByZWQgbGluZSBpcyB0aGUgMToxIGxpbmUgb24gd2hpY2ggYWxsIG9mIHRoZSBwb2ludHMgd291bGQgbGllIGlmIE9ic2VydmVkIGV4YWN0bHkgbWF0Y2hlZCBFeHBlY3RlZC5dCgpgYGB7cn0KcCA8LSBnZ3Bsb3QocmVzdWx0LCBhZXMoeCA9IEV4cGVjdGVkLCB5ID0gT2JzZXJ2ZWQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIsIAogICAgICAgICAgICAgIGNvbG9yID0gInJlZCIpICsKICB0aGVtZV9idygpCnAKYGBgClRoYXQgZG9lc24ndCBsb29rIHRvIGJhZCwgYnV0IGl0J3Mgb25seSBzaG93aW5nIHRoZSAqbWVhbiogb2YgdGhlIHNpbXVsYXRpb25zLiBJdCdzIG5vdCBzaG93aW5nIGFueXRoaW5nIGFib3V0IHRoZSByYW5nZSBvZiBwbGF1c2libGUgdmFsdWVzLiBMZXQncyBhZGQgdGhhdCB0byB0aGUgcGxvdCBhbmQgc2VlIHdoYXQgaXQgbG9va3MgbGlrZS4KCmBgYHtyfQpwIDwtIGdncGxvdChyZXN1bHQsIGFlcyh4ID0gRXhwZWN0ZWQsIHkgPSBPYnNlcnZlZCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHhtaW4gPSBMb3dlcl8yLjUsIHhtYXggPSBVcHBlcl85Ny41LCB3aWR0aCA9IDAuMDIpKSArCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCAKICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiKSArCiAgdGhlbWVfYncoKQpwCmBgYAoKU28gaXQgYXBwZWFycyBmb3IgdGhlc2UgZGF0YSB0aGVyZSdzIGEgcmVhc29uYWJseSBnb29kIGZpdCBiZXR3ZWVuIE9ic2VydmVkIGFuZCBFeHBlY3RlZC4gVGhlcmUgY2VydGFpbmx5IGlzbid0IGEgY29uc2lzdGVudCBwYXR0ZXJuIG9mIG1pc21hdGNoLgoKIyMgTGFiIDkKCkkndmUgbWVudGlvbmVkIHNlbGYtaW5jb21wYXRpYmlsaXR5IGFsbGVsZXMgc2V2ZXJhbCB0aW1lcyBpbiBsZWN0dXJlLiBJbiB0aGlzIHdlZWsncyBleGVyY2lzZSB3ZSdyZSBnb2luZyB0byBleHBsb3JlIHNlcXVlbmNlIHZhcmlhdGlvbiBpbiBhIHNhbXBsZSBvZiB0aGVtLiBNb3JlIHByZWNpc2VseSwgSSdtIGdvaW5nIHRvIHByb3ZpZGUgeW91IHdpdGggYSB0cmVlIGRlc2NyaWJpbmcgcmVsYXRpb25zaGlwcyBhbW9uZyBzZWxmLWluY29tcGF0aWJpbGl0eSBhbGxlbGVzIGluICpTb2xhbnVtKiwgdGhlIGdlbnVzIHRoYXQgaW5jbHVkZXMgcG90YXRvZXMsIHRvbWF0b2VzLCBhbmQgZWdncGxhbnRzLiBUaGUgZGF0YSBhcmUgZGVyaXZlZCBmcm9tIFJpY2htYW4gYW5kIEtvaG4uXltSaWNobWFuLCBBLkQuLCBhbmQgSi5SLiBLb2huLiAgMjAwMC4gIEV2b2x1dGlvbmFyeSBnZW5ldGljcyBvZiBzZWxmLWluY29tcGF0aWJpbGl0eSBpbiB0aGUgU29sYW5hY2VhZS4gICpQbGFudCBNb2xlY3VsYXIgQmlvbG9neSogIDQyOjE2OS0xNzkuIGRvaTogWzEwLjEwMjMvQToxMDA2MzM2MjA2NjM3XShodHRwczovL2R4LmRvaS5vcmcvMTAuMTAyMy9BOjEwMDYzMzYyMDY2MzcpXSBUaGUgb3JpZ2luYWwgZGF0YSBzZXQgaW5jbHVkZWQgNjcgbnVjbGVvdGlkZSBzZXF1ZW5jZXMuIEFmdGVyIGFsaWduaW5nIHRoZSBzZXF1ZW5jZXMgd2l0aCBNdXNjbGUgYW5kIGVsaW1pbmF0aW5nIGEgZmV3IGR1cGxpY2F0ZXMsIDYzIHJlbWFpbi4gSSBlc3RpbWF0ZWQgYSBwaHlsb2dlbmV0aWMgdHJlZSBvZiByZWxhdGlvbnNoaXBzIHdpdGggd2l0aCBNci4gQmF5ZXMgYXNzdW1pbmcgYSBzdHJpY3QgbW9sZWN1bGFyIGNsb2NrLF5bSSB1c2VkIHRoZSBzYW1lIHBhcmFtZXRlcnMgYXMgd2l0aCB0aGUgQURIIGV4YW1wbGUgYWJvdmUuXSBhbmQgeW91J2xsIGZpbmQgdGhlIHJlc3VsdGluZyBjb25zZW5zdXMgdHJlZSBhdCBbaHR0cDovL2Rhcndpbi5lZWIudWNvbm4uZWR1L2VlYjM0OC1yZXNvdXJjZXMvc1JOYXNlLmNsb2NrLmNvbi50cmVdKGh0dHA6Ly9kYXJ3aW4uZWViLnVjb25uLmVkdS9lZWIzNDgtcmVzb3VyY2VzL3NSTmFzZS5jbG9jay5jb24udHJlKS5eW05vdGU6IFlvdSBjYW4gZWl0aGVyIGRvd25sb2FkIHRoZSBmaWxlIHRvIHlvdXIgaGFyZCBkcml2ZSwgb3IgeW91IGNhbiByZWFkIGl0IGRpcmVjdGx5IHdpdGggYHJlYWQubmV4dXMoKWAsIHB1dHRpbmcgaW4gdGhlIGZ1bGwgVVJMIChpbiBxdW90ZXMpIGluc3RlYWQgb2YgdGhlIGZpbGVuYW1lLl0gCgpVc2luZyB0aGlzIHRyZWUsIGV4cGxvcmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG9ic2VydmVkIGNvYWxlc2NlbmNlIHRpbWVzLCBpLmUuLCB0aGUgZXN0aW1hdGVkIGJyYW5jaGluZyB0aW1lcyBpbiB0aGUgb3V0cHV0IGZyb20gTXIuIEJheWVzLCB3aXRoIHRob3NlIGV4cGVjdGVkLCBpLmUuLCB0aGUgYnJhbmNoaW5nIHRpbWVzIHNpbXVsYXRlZCBieSBgbXMoKWAuIFRoZSBgY29tcGFyZV9jb2FsZXNjZW50KClgIGZ1bmN0aW9uIGFib3ZlIGFuZCB0aGUgY29kZSBmb2xsb3dpbmcgaXQgdGhhdCBzaG93cyBob3cgdG8gbG9vayBhdCB0aGUgbnVtYmVycyBhbmQgaG93IHRvIHZpc3VhbGl6ZSB0aGUgcmVzdWx0cyBzaG91bGQgbWFrZSB0aGF0IHByZXR0eSBlYXN5LiBPbmNlIHlvdSd2ZSBkb25lIHRoYXQsIGFuc3dlciB0aGVzZSB0d28gcXVlc3Rpb25zOgoKMS4gV2hhdCBzeXN0ZW1hdGljIGRpZmZlcmVuY2VzIGJldHdlZW4gb2JzZXJ2ZWQgYW5kIGV4cGVjdGVkIGNvYWxlc2NlbmNlIHRpbWVzIGRvIHlvdSBzZWU/CgoyLiBHaXZlbiB3aGF0IEkndmUgc2FpZCBhYm91dCBzZWxmLWluY29tcGF0aWJpbGl0eSBpbiBsZWN0dXJlIGFuZCB3aGF0IFJpY2htYW4gYW5kIEtvaG4gc2F5IGFib3V0IGl0IGluIHRoZWlyIHBhcGVyLCBob3cgd291bGQgeW91IGV4cGxhaW4gdGhlIGRpc2NyZXBhbmNpZXMgdGhhdCB5b3Ugc2VlLgo=