Acknowledgement The main idea of the microbial analysis and the phyloseq dataset are coming from this paper Temporal and spatial variation of the human microbiota during pregnancy The idea which is underlying this analysis is to use clustering to discover the dynamic of the gut community via Community State Types (CST). CSTs are discrete set of clusters.

Initialize:

## [1] '1.34.0'
## [1] '3.3.5'
## [1] '2.1.2'
## [1] '1.2.6'
## [1] '0.8.6'

Dataset from stool

da<- load('RDA/PregnancyClosed15.Rdata')
site <- "Stool"
phy <- PSPreg[[site]]
phy
## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 1271 taxa and 580 samples ]
## sample_data() Sample Data:       [ 580 samples by 64 sample variables ]
## tax_table()   Taxonomy Table:    [ 1271 taxa by 7 taxonomic ranks ]
## phy_tree()    Phylogenetic Tree: [ 1271 tips and 1270 internal nodes ]

Remove rare taxa Transform the data (proportions):

## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 894 taxa and 580 samples ]
## sample_data() Sample Data:       [ 580 samples by 64 sample variables ]
## tax_table()   Taxonomy Table:    [ 894 taxa by 7 taxonomic ranks ]
## phy_tree()    Phylogenetic Tree: [ 894 tips and 893 internal nodes ]

We are not doing differential abundance analysis here, so the proportion transformation is used for exploratory analyses only.

Cluster into CSTs

The vaginal community is dominated by closely related, but functionally distinct, Lactobacillus species. Therefore it is better to use a non-phylogenetically aware distance measure so as to be able to separate these species. Start with an MDS (or PCoA) ordination:

##  [1] 42.210864 22.612218 12.083443  9.496256  8.919936  6.947028  6.888458
##  [8]  5.240856  4.622571  4.539161  4.246411  3.870323  3.374326  3.117964
## [15]  2.861045  2.852497  2.468666  2.355515  2.090535  1.991523
## [1] -0.3676292 -0.3957017 -0.4337434 -0.4744555 -0.5301270 -0.8299508

Denoise distance matrix

We would like to clean some of the noise from the data by restricting this to the truly significant dimensions. The top 5 eigenvalues are clearly very significant, but let’s keep all the positive eigenvalues that clearly exceed the magnitude of the smallest negative eigenvalues:

h_sub5 <- hist(evs[6:length(evs)], 100)

plot(h_sub5$mids, h_sub5$count, log="y", type='h', lwd=10, lend=2)

Looks like eigenvalues 6 and 7 still stand out, so we’ll go with 7 MDS dimensions.

Determine number of clusters

We will use the gap statistic to indicate the number of clusters in this data:

The gap statistic strongly suggests at least three clusters, but makes another big jump at K=5 before the slope gets a lot smaller. So, K=5 it is.

Cluster into CSTs

Perform PAM 5-fold clusters:

Evaluate clustering

Inspect the results in MDS and NMDS ordinations:

## Run 0 stress 0.18648 
## Run 1 stress 0.190787 
## Run 2 stress 0.1862701 
## ... New best solution
## ... Procrustes: rmse 0.01168006  max resid 0.09976727 
## Run 3 stress 0.1933471 
## Run 4 stress 0.201474 
## Run 5 stress 0.1954427 
## Run 6 stress 0.1922218 
## Run 7 stress 0.1879763 
## Run 8 stress 0.1921214 
## Run 9 stress 0.1884075 
## Run 10 stress 0.2235917 
## Run 11 stress 0.1919761 
## Run 12 stress 0.198366 
## Run 13 stress 0.1877754 
## Run 14 stress 0.190696 
## Run 15 stress 0.187102 
## Run 16 stress 0.1891335 
## Run 17 stress 0.1956618 
## Run 18 stress 0.1917857 
## Run 19 stress 0.1842801 
## ... New best solution
## ... Procrustes: rmse 0.01003169  max resid 0.09694101 
## Run 20 stress 0.200065 
## *** No convergence -- monoMDS stopping criteria:
##      1: no. of iterations >= maxit
##     11: stress ratio > sratmax
##      8: scale factor of the gradient < sfgrmin

Heatmaps for taxa per clusters

The ordinations offer support for these being legitimate clusters, even if they are not perfect and some samples look like they might be mixtures of two clusters. Let’s take a look at the heatmaps of each cluster for additional perspective:

Boxplots

Boxplots for each Species in the five clusters. We will investigate shannon index with non parametric Kruskal test for each taxa among the five clusters

Post hoc

Post hoc by implementing Conover’s test for the significant p_values using shannon index with adjusted p_value is (Benjamini-Hochberg).

LS0tDQp0aXRsZTogJ0NvbW11bml0eSBTdGF0ZSBUeXBlcyAoQ1NUKScNCmF1dGhvcjogIldpc2FtIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICAgIHRvYzogdHJ1ZQ0KICAgICAgdG9jX2RlcHRoOiA0DQogICAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQoqKkFja25vd2xlZGdlbWVudCoqIFRoZSBtYWluIGlkZWEgb2YgdGhlIG1pY3JvYmlhbCBhbmFseXNpcyBhbmQgdGhlIHBoeWxvc2VxIGRhdGFzZXQgYXJlIGNvbWluZyBmcm9tIHRoaXMgcGFwZXIgW1RlbXBvcmFsIGFuZCBzcGF0aWFsIHZhcmlhdGlvbiBvZiB0aGUgaHVtYW4gbWljcm9iaW90YSBkdXJpbmcgcHJlZ25hbmN5XShodHRwczovL3d3dy5wbmFzLm9yZy9jb250ZW50LzExMi8zNS8xMTA2MCkNClRoZSBpZGVhIHdoaWNoIGlzIHVuZGVybHlpbmcgdGhpcyBhbmFseXNpcyBpcyB0byB1c2UgY2x1c3RlcmluZyB0byBkaXNjb3ZlciB0aGUgZHluYW1pYyBvZiB0aGUgZ3V0IGNvbW11bml0eSB2aWEgQ29tbXVuaXR5IFN0YXRlIFR5cGVzIChDU1QpLiBDU1RzIGFyZSBkaXNjcmV0ZSBzZXQgb2YgY2x1c3RlcnMuDQoNCg0KDQpJbml0aWFsaXplOg0KYGBge3IgaW5pdCwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoInBoeWxvc2VxIik7IHBhY2thZ2VWZXJzaW9uKCJwaHlsb3NlcSIpDQpsaWJyYXJ5KCJnZ3Bsb3QyIik7IHBhY2thZ2VWZXJzaW9uKCJnZ3Bsb3QyIikNCmxpYnJhcnkoImNsdXN0ZXIiKTsgcGFja2FnZVZlcnNpb24oImNsdXN0ZXIiKQ0KbGlicmFyeSgiaWdyYXBoIik7IHBhY2thZ2VWZXJzaW9uKCJpZ3JhcGgiKQ0KbGlicmFyeSgibWFya292Y2hhaW4iKTsgcGFja2FnZVZlcnNpb24oIm1hcmtvdmNoYWluIikNCmxpYnJhcnkoIlJDb2xvckJyZXdlciIpDQpsaWJyYXJ5KCJncmlkRXh0cmEiKQ0KDQpzZXQuc2VlZCgxMDApDQpkZWZhdWx0LnBhciA8LSBwYXIobm8ucmVhZG9ubHkgPSBUUlVFKQ0Kb3B0aW9ucyhzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQp0aGVtZV9zZXQodGhlbWVfYncoKSkNCiMgRVhDTFVERU1BUkdJTkFMIGlzIGEgZmxhZyB0byBleGNsdWRlIG1hcmdpbmFsbHkgcHJldGVybSBiaXJ0aHMgKD0zNyB3ZWVrcykgaW4gdGhlIGxhdGVyIGFuYWx5c2lzDQpFWENMVURFTUFSR0lOQUwgPSBUUlVFDQpgYGANCg0KDQoqICoqUGh5bG9zZXEgZGF0YXNldCoqDQpGcm9tIHRoZSBzYW1lIHBhcGVyIFtUZW1wb3JhbCBhbmQgc3BhdGlhbCB2YXJpYXRpb24gb2YgdGhlIGh1bWFuIG1pY3JvYmlvdGEgZHVyaW5nIHByZWduYW5jeV0oaHR0cHM6Ly93d3cucG5hcy5vcmcvY29udGVudC8xMTIvMzUvMTEwNjApDQoNCiMjIyBEYXRhc2V0IGZyb20gc3Rvb2wNCg0KDQpgYGB7ciBkYXRhX3ZhZ2luYSwgZWNobz1ULCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCg0KZGE8LSBsb2FkKCdSREEvUHJlZ25hbmN5Q2xvc2VkMTUuUmRhdGEnKQ0Kc2l0ZSA8LSAiU3Rvb2wiDQpwaHkgPC0gUFNQcmVnW1tzaXRlXV0NCnBoeQ0KDQpgYGANCioqUmVtb3ZlIHJhcmUgdGF4YSoqIA0KVHJhbnNmb3JtIHRoZSBkYXRhIChwcm9wb3J0aW9ucyk6DQpgYGB7ciB0cmFuc2Zvcm0tZGF0YSwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBoeV9jb21wIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKHBoeSwgZnVuY3Rpb24oT1RVKSBPVFUvc3VtKE9UVSkpDQpwaHlfY29tcDwtcHJ1bmVfdGF4YSh0YXhhX3N1bXMocGh5X2NvbXApID4gMCwgcGh5X2NvbXApDQpwaHlfY29tcA0KDQpgYGANCldlIGFyZSBub3QgZG9pbmcgZGlmZmVyZW50aWFsIGFidW5kYW5jZSBhbmFseXNpcyBoZXJlLCBzbyB0aGUgcHJvcG9ydGlvbiB0cmFuc2Zvcm1hdGlvbiBpcyB1c2VkIGZvciBleHBsb3JhdG9yeSBhbmFseXNlcyBvbmx5Lg0KDQojIENsdXN0ZXIgaW50byBDU1RzDQoNClRoZSB2YWdpbmFsIGNvbW11bml0eSBpcyBkb21pbmF0ZWQgYnkgY2xvc2VseSByZWxhdGVkLCBidXQgZnVuY3Rpb25hbGx5IGRpc3RpbmN0LCBMYWN0b2JhY2lsbHVzIHNwZWNpZXMuIFRoZXJlZm9yZSBpdCBpcyBiZXR0ZXIgdG8gdXNlIGEgbm9uLXBoeWxvZ2VuZXRpY2FsbHkgYXdhcmUgZGlzdGFuY2UgbWVhc3VyZSBzbyBhcyB0byBiZSBhYmxlIHRvIHNlcGFyYXRlIHRoZXNlIHNwZWNpZXMuIFN0YXJ0IHdpdGggYW4gTURTIChvciBQQ29BKSBvcmRpbmF0aW9uOg0KYGBge3IgTURTLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KYnJheWRpc3QgPC0gcGh5bG9zZXE6OmRpc3RhbmNlKHBoeV9jb21wLCBtZXRob2Q9ImJyYXkiKQ0Kb3JkID0gb3JkaW5hdGUocGh5X2NvbXAsIG1ldGhvZCA9ICJNRFMiLCBkaXN0YW5jZSA9IGJyYXlkaXN0KQ0KcGxvdF9zY3JlZShvcmQpICsgeGxpbShhcy5jaGFyYWN0ZXIoc2VxKDEsMTIpKSkgKyBnZ3RpdGxlKCJNRFMtYnJheSBvcmRpbmF0aW9uIGVpZ2VudmFsdWVzIikNCmV2cyA8LSBvcmQkdmFsdWUkRWlnZW52YWx1ZXMNCnByaW50KGV2c1sxOjIwXSkNCnByaW50KHRhaWwoZXZzKSkNCmBgYA0KDQojIyBEZW5vaXNlIGRpc3RhbmNlIG1hdHJpeA0KDQpXZSB3b3VsZCBsaWtlIHRvIGNsZWFuIHNvbWUgb2YgdGhlIG5vaXNlIGZyb20gdGhlIGRhdGEgYnkgcmVzdHJpY3RpbmcgdGhpcyB0byB0aGUgdHJ1bHkgc2lnbmlmaWNhbnQgZGltZW5zaW9ucy4gVGhlIHRvcCA1IGVpZ2VudmFsdWVzIGFyZSBjbGVhcmx5IHZlcnkgc2lnbmlmaWNhbnQsIGJ1dCBsZXQncyBrZWVwIGFsbCB0aGUgcG9zaXRpdmUgZWlnZW52YWx1ZXMgdGhhdCBjbGVhcmx5IGV4Y2VlZCB0aGUgbWFnbml0dWRlIG9mIHRoZSBzbWFsbGVzdCBuZWdhdGl2ZSBlaWdlbnZhbHVlczoNCmBgYHtyIFBDb0EtY3V0b2ZmMiwgd2FybmluZz1GQUxTRX0NCmhfc3ViNSA8LSBoaXN0KGV2c1s2Omxlbmd0aChldnMpXSwgMTAwKQ0KcGxvdChoX3N1YjUkbWlkcywgaF9zdWI1JGNvdW50LCBsb2c9InkiLCB0eXBlPSdoJywgbHdkPTEwLCBsZW5kPTIpDQpgYGANCg0KTG9va3MgbGlrZSBlaWdlbnZhbHVlcyA2IGFuZCA3IHN0aWxsIHN0YW5kIG91dCwgc28gd2UnbGwgZ28gd2l0aCA3IE1EUyBkaW1lbnNpb25zLg0KDQojIyBEZXRlcm1pbmUgbnVtYmVyIG9mIGNsdXN0ZXJzDQpXZSB3aWxsIHVzZSB0aGUgZ2FwIHN0YXRpc3RpYyB0byBpbmRpY2F0ZSB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzIGluIHRoaXMgZGF0YToNCmBgYHtyIGdhcC1zdGF0LCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KTkRJTSA8LSA3DQp4IDwtIG9yZCR2ZWN0b3JzWywxOk5ESU1dICAjIHJvd3M9c2FtcGxlLCBjb2xzPU1EUyBheGVzLCBlbnRyaWVzID0gdmFsdWUNCnBhbVBDb0EgPSBmdW5jdGlvbih4LCBrKSB7DQogICAgbGlzdChjbHVzdGVyID0gcGFtKHhbLDE6Ml0sIGssIGNsdXN0ZXIub25seSA9IFRSVUUpKQ0KfQ0KZ3MgPSBjbHVzR2FwKHgsIEZVTiA9IHBhbVBDb0EsIEsubWF4ID0gMTIsIEIgPSA1MCkNCnBsb3RfY2x1c2dhcChncykgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDAsIDEyLCAyKSkpDQpgYGANCg0KVGhlIGdhcCBzdGF0aXN0aWMgc3Ryb25nbHkgc3VnZ2VzdHMgYXQgbGVhc3QgdGhyZWUgY2x1c3RlcnMsIGJ1dCBtYWtlcyBhbm90aGVyIGJpZyBqdW1wIGF0IEs9NSBiZWZvcmUgdGhlIHNsb3BlIGdldHMgYSBsb3Qgc21hbGxlci4gU28sIEs9NSBpdCBpcy4NCg0KIyMgQ2x1c3RlciBpbnRvIENTVHMNCg0KUGVyZm9ybSBQQU0gNS1mb2xkIGNsdXN0ZXJzOg0KYGBge3IgcGFtLWs1LCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KSyA8LSA1DQp4IDwtIG9yZCR2ZWN0b3JzWywxOk5ESU1dDQpjbHVzdCA8LSBhcy5mYWN0b3IocGFtKHgsIGs9SywgY2x1c3Rlci5vbmx5PVQpKQ0KIyBTV0FQUElORyBUSEUgQVNTSUdOTUVOVCBPRiAyIEFORCAzIFRPIE1BVENIIFJBVkVMIENTVCBFTlVNRVJBVElPTg0KY2x1c3RbY2x1c3Q9PTJdIDwtIE5BDQpjbHVzdFtjbHVzdD09M10gPC0gMg0KY2x1c3RbaXMubmEoY2x1c3QpXSA8LSAzDQpzYW1wbGVfZGF0YShwaHlfY29tcCkkQ1NUIDwtIGNsdXN0DQpDU1RzIDwtIGFzLmNoYXJhY3RlcihzZXEoSykpDQpgYGANCg0KIyMgRXZhbHVhdGUgY2x1c3RlcmluZw0KDQpJbnNwZWN0IHRoZSByZXN1bHRzIGluIE1EUyBhbmQgTk1EUyBvcmRpbmF0aW9uczoNCmBgYHtyIHNlZS1wYW0tazUsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpDU1RDb2xvcnMgPC0gYnJld2VyLnBhbCg2LCJQYWlyZWQiKVtjKDEsMywyLDUsNCw2KV0gIyBMZW5ndGggNiBmb3IgY29uc2lzdGVuY3kgd2l0aCBwcmUtcmV2aXNpb24gDQpuYW1lcyhDU1RDb2xvcnMpIDwtIENTVHMNCkNTVENvbG9yU2NhbGUgPC0gc2NhbGVfY29sb3VyX21hbnVhbChuYW1lID0gIkNTVCIsIHZhbHVlcyA9IENTVENvbG9yc1sxOjVdKQ0KQ1NURmlsbFNjYWxlIDwtIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiQ1NUIiwgdmFsdWVzID0gQ1NUQ29sb3JzWzE6NV0pDQoNCm9rPC1vcmRpbmF0ZShwaHlfY29tcCwgbWV0aG9kPSJOTURTIiwgZGlzdGFuY2U9YnJheWRpc3QpDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChyZXN1bHRzID0gImhpZGUiKQ0KYGBgDQoNCg0KYGBge3Igc2VlLXBhbS1wbG90LCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGxvdF9vcmRpbmF0aW9uKHBoeV9jb21wLG9rICwgY29sb3I9IkNTVCIpICsgQ1NUQ29sb3JTY2FsZSArIGdndGl0bGUoIk5NRFMgLS0gYnJheSAtLSBCeSBDbHVzdGVyIikNCg0KYGBgDQoNCiMgSGVhdG1hcHMgZm9yIHRheGEgcGVyIGNsdXN0ZXJzDQpUaGUgb3JkaW5hdGlvbnMgb2ZmZXIgc3VwcG9ydCBmb3IgdGhlc2UgYmVpbmcgbGVnaXRpbWF0ZSBjbHVzdGVycywgZXZlbiBpZiB0aGV5IGFyZSBub3QgcGVyZmVjdCBhbmQgc29tZSBzYW1wbGVzIGxvb2sgbGlrZSB0aGV5IG1pZ2h0IGJlIG1peHR1cmVzIG9mIHR3byBjbHVzdGVycy4gTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGhlYXRtYXBzIG9mIGVhY2ggY2x1c3RlciBmb3IgYWRkaXRpb25hbCBwZXJzcGVjdGl2ZToNCg0KYGBge3IgY2x1c3QtZGl2ZXJzZSwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgb3V0LndpZHRoPSI1MCUifQ0KI3RheGEub3JkZXIgPC0gbmFtZXMoc29ydCh0YXhhX3N1bXMocGh5X2NvbXApKSkNCmZvcihDU1QgaW4gQ1NUcykgew0KICBwc2htIDwtIHBydW5lX3RheGEobmFtZXMoc29ydCh0YXhhX3N1bXMocGh5X2NvbXApLCBUKSlbMTozMF0sIHBoeV9jb21wKQ0KICBwc2htIDwtIHBydW5lX3NhbXBsZXMoc2FtcGxlX2RhdGEocHNobSkkQ1NUID09IENTVCwgcHNobSkNCiAgcHJpbnQocGxvdF9oZWF0bWFwKHBzaG0sIHRheGEubGFiZWw9IlNwZWNpZXMiLCB0YXhhLm9yZGVyPXRheGEub3JkZXIpICsgZ2d0aXRsZShwYXN0ZSgiQ1NUOiIsIENTVCkpKQ0KDQoNCn0NCg0KYGBgDQoNCg0KDQpgYGB7ciBwaHlfMzAsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0YXhhLm9yZGVyMTwtbmFtZXMoc29ydCh0YXhhX3N1bXMocHNobSksIFQpKVsxOjMwXQ0KDQpwaHlfMzA8LXBydW5lX3RheGEodGF4YS5vcmRlcjEsIHBoeSkNCiMjIyBDaGVjayB1cCBmb3IgcmFuZG9tDQojVmlldyhvdHVfdGFibGUocGh5XzMwKUAuRGF0YVsnMTkwMTAwMjI4OCcsJzQ0NjgyMzQnXSkNCiNWaWV3KG90dV90YWJsZShwaHkpQC5EYXRhWycxOTAxMDAyMjg4JywnNDQ2ODIzNCddKQ0KI1ZpZXcob3R1X3RhYmxlKHBoeV9jb21wKUAuRGF0YVsnMTkwMTAwMjI4OCcsJzQ0NjgyMzQnXSkNCnBoeV8zMA0KYGBgDQoNCg0KYGBge3IgcGh5XzMwX21ldGFkYXRhLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KdGF4YS5vcmRlciA8LSBuYW1lcyhzb3J0KHRheGFfc3VtcyhwaHlfY29tcCkpKQ0KZGF0YWxpc3Q8LWxpc3QoKQ0KZm9yKENTVCBpbiBDU1RzKSB7DQogIHBzaG0gPC0gcHJ1bmVfdGF4YShuYW1lcyhzb3J0KHRheGFfc3VtcyhwaHlfY29tcCksIFQpKVsxOjMwXSwgcGh5X2NvbXApDQogIHBzaG0gPC0gcHJ1bmVfc2FtcGxlcyhzYW1wbGVfZGF0YShwc2htKSRDU1QgPT0gQ1NULCBwc2htKQ0KICBkZjwtIGdldF92YXJpYWJsZShwc2htKQ0KICANCiAgZGF0YWxpc3RbW0NTVF1dIDwtIGRmDQoNCn0NCmRmMTwtZG8uY2FsbChyYmluZC5kYXRhLmZyYW1lLCBkYXRhbGlzdCkNCnJvd25hbWVzKGRmMSk8LWRmMSRTYW1wbGVJRA0Kc2FtcGxlX2RhdGEocGh5XzMwKTwtIGRmMQ0KYGBgDQoNCg0KIyBCb3hwbG90cyANCkJveHBsb3RzIGZvciBlYWNoICoqU3BlY2llcyoqIGluIHRoZSBmaXZlIGNsdXN0ZXJzLiBXZSB3aWxsIGludmVzdGlnYXRlIHNoYW5ub24gaW5kZXggd2l0aCBub24gcGFyYW1ldHJpYyBLcnVza2FsIHRlc3QgZm9yIGVhY2ggdGF4YSBhbW9uZyB0aGUgZml2ZSBjbHVzdGVycw0KDQpgYGB7ciBjbHVzdC1kaXZlcnNlX2JveHBsb3QsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG91dC53aWR0aD0iMjUlIn0NCnRoZW1lX3NldCh0aGVtZV9idyhiYXNlX3NpemUgPSAyMCkpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2diZWVzd2FybSkNCmxpYnJhcnkoY29ub3Zlci50ZXN0KQ0KI2xpYnJhcnkobWljcm9iaW9tZSkNCmRmMSRzaGFubm9uPC1lc3RpbWF0ZV9yaWNobmVzcyhwaHlfMzAsIG1lYXN1cmVzID0gJ1NoYW5ub24nKQ0KZGYxJENTVDwtZmFjdG9yKGRmMSRDU1QsIGxldmVscyA9IGMoJzEnLCcyJywnMycsJzQnLCc1JykpDQoNCiNwaHlfMzBfY29tcDwtdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMocGh5XzMwLCBmdW5jdGlvbihPVFUpIE9UVS9zdW0oT1RVKSkNCg0KI2lkZW50aWNhbCh0KGdldF90YXhhKHBoeV8zMCkpLCBhYnVuZGFuY2VzKHBoeV8zMCkpDQpmb3IgKHRheCBpbiByZXYodGF4YS5vcmRlcjEpKSB7DQogIGRmMSR0YXhhPC0gdChnZXRfdGF4YShwaHlfMzBfY29tcCkpW3RheCxdDQogICNkZiR0YXhhPC0gb3R1X3RhYmxlKHBzKUAuRGF0YVt0YXgsXQ0KICBwdjwtIHJvdW5kKGtydXNrYWwudGVzdChzaGFubm9uJFNoYW5ub24gfiBDU1QsIGRhdGEgPSBkZjEpJHAudmFsdWUsIDMpDQogICNwdl9zaGFuPC0gcm91bmQoa3J1c2thbC50ZXN0KHNoYW5ub24kU2hhbm5vbiB+IENTVCwgZGF0YSA9IGRmMSkkcC52YWx1ZSwgMykNCiAgdDwtIGFzLmRhdGEuZnJhbWUodGF4X3RhYmxlKHBoeV8zMF9jb21wKVt0YXgsXSkkU3BlY2llcw0KICBwcmludCh0KQ0KICBwPC0gZ2dwbG90KGRmMSwgYWVzKHggPSBmYWN0b3IoQ1NUKSwgeSA9IHRheGEpKSsgeWxpbSgwLDEpICsgZ2VvbV9iZWVzd2FybShjb2xvciA9ICJkYXJrYmx1ZSIsIHNpemU9IDAuMykrIGdndGl0bGUocGFzdGUwKHQpKSsgeWxhYigiUmVsYXRpdmUgYWJ1bmRhbmNlIikgK3hsYWIoIkNvbW11bml0eSBTdGF0ZSBUeXBlcyAoQ1NUKSIpKyBsYWJzKHRpdGxlID0gcGFzdGUwKHQpLCBzdWJ0aXRsZSA9IHBhc3RlMCgncF92YWx1ZSBmb3IgU2hhbm5vbiBpczogJywgcHYpKSANCiAgcHJpbnQocCkNCg0KfQ0KYGBgDQoNCiMgUG9zdCBob2MNClBvc3QgaG9jIGJ5IGltcGxlbWVudGluZyBDb25vdmVy4oCZcyB0ZXN0IGZvciB0aGUgc2lnbmlmaWNhbnQgcF92YWx1ZXMgdXNpbmcgKipzaGFubm9uIGluZGV4Kiogd2l0aCBhZGp1c3RlZCBwX3ZhbHVlIGlzIChCZW5qYW1pbmktSG9jaGJlcmcpLg0KDQoNCmBgYHtyIHBvc3RfaG9jLCBtZXNzYWdlPUZBTFNFLGV2YWw9VFJVRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoImNvbm92ZXIudGVzdCIpDQpjb3Y8LWNvbm92ZXIudGVzdDo6Y29ub3Zlci50ZXN0KGRmMSRzaGFubm9uJFNoYW5ub24sIGRmMSRDU1QsIGt3ID0gVCwgbWV0aG9kPSJiaCIpDQoNCnByaW50KGNvdikNCmBgYA0KDQoNCiFbXShwb3N0X2hvYy5wbmcpe3dpZHRoPTE1MCV9DQo=