1.加载R包和测试数据

library(vegan)
Loading required package: permute
Loading required package: lattice
This is vegan 2.5-7
library(ape)
library(picante)
Loading required package: nlme
library(vegan)
nifhotu_norep <- read.delim("./data/nifhotu_no_reps.txt", row.names=1)
env_norep <- read.delim("./data/env_no_reps.txt", row.names=1)
tree <- read.tree("./data/tree")

2.让树文件与OTU表相匹配

tree$tip.label <- stringr::str_replace_all(tree$tip.label,"'","")
prune_tree<-prune.sample(nifhotu_norep,tree)
tip<-prune_tree$tip.label
coln<-colnames(nifhotu_norep)
m<-NULL
for(i in 1:length(coln)){
  if(!coln[i]%in%tip){
    print(paste("delete this OTU from tree:",coln[i]))
    m<-cbind(m,coln[i])
  }
}
[1] "delete this OTU from tree: OTU_10179"
[1] "delete this OTU from tree: OTU_10329"
[1] "delete this OTU from tree: OTU_113977"
[1] "delete this OTU from tree: OTU_122"
[1] "delete this OTU from tree: OTU_133570"
[1] "delete this OTU from tree: OTU_159"
[1] "delete this OTU from tree: OTU_22258"
[1] "delete this OTU from tree: OTU_24594"
[1] "delete this OTU from tree: OTU_26066"
[1] "delete this OTU from tree: OTU_267595"
[1] "delete this OTU from tree: OTU_35216"
[1] "delete this OTU from tree: OTU_38790"
[1] "delete this OTU from tree: OTU_43486"
[1] "delete this OTU from tree: OTU_45378"
[1] "delete this OTU from tree: OTU_53268"
[1] "delete this OTU from tree: OTU_57855"
[1] "delete this OTU from tree: OTU_87080"
m<-as.vector(m)
nifhotu_norep<-nifhotu_norep[,!colnames(nifhotu_norep)%in%m]

3.获得OTU间遗传发育距离

otu_phydist <- cophenetic(prune_tree)

4.基于生态位距离的遗传发育信号检验

4.1 RDA分析并获得影响显著的环境因子

#distance calculation
bray_dist_norep <- vegdist(nifhotu_norep,method = "bray")
#rda analysis
otu_dbrda_norep <- dbrda(sqrt(bray_dist_norep)~.,data=env_norep,add = TRUE)
anova(otu_dbrda_norep,permutations = how(nperm = 999))
Permutation test for dbrda under reduced model
Permutation: free
Number of permutations: 999

Model: dbrda(formula = sqrt(bray_dist_norep) ~ pH + tn + tp + tk + ep + ek + emo + cec + den + nl + fl + sl + wc, data = env_norep, add = TRUE)
         Df SumOfSqs     F Pr(>F)    
Model    12   5.5318 1.184  0.001 ***
Residual 15   5.8400                 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#forward selection
step_forward_norep <- ordistep(dbrda(sqrt(bray_dist_norep)~1,data=env_norep,add = TRUE),scope = formula(otu_dbrda_norep),direction="forward")

Start: sqrt(bray_dist_norep) ~ 1 

      Df    AIC      F Pr(>F)   
+ pH   1 68.271 2.7168  0.005 **
+ tp   1 69.375 1.6063  0.005 **
+ nl   1 69.639 1.3473  0.010 **
+ tn   1 69.727 1.2613  0.040 * 
+ fl   1 69.815 1.1756  0.085 . 
+ emo  1 69.897 1.0967  0.150   
+ den  1 69.931 1.0633  0.195   
+ tk   1 69.959 1.0363  0.305   
+ wc   1 69.958 1.0380  0.325   
+ cec  1 69.971 1.0246  0.370   
+ sl   1 70.008 0.9889  0.560   
+ ep   1 70.144 0.8588  0.940   
+ ek   1 70.194 0.8106  0.995   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Step: sqrt(bray_dist_norep) ~ pH 

      Df    AIC      F Pr(>F)   
+ tn   1 68.827 1.3225  0.010 **
+ tp   1 68.994 1.1668  0.045 * 
+ emo  1 69.046 1.1174  0.075 . 
+ den  1 69.017 1.1445  0.085 . 
+ fl   1 69.055 1.1095  0.130   
+ nl   1 69.083 1.0836  0.140   
+ wc   1 69.071 1.0949  0.155   
+ tk   1 69.068 1.0970  0.160   
+ cec  1 69.083 1.0832  0.170   
+ sl   1 69.114 1.0548  0.340   
+ ep   1 69.284 0.8967  0.850   
+ ek   1 69.321 0.8624  0.950   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Step: sqrt(bray_dist_norep) ~ pH + tn 

      Df    AIC      F Pr(>F)  
+ tp   1 69.528 1.1400  0.055 .
+ emo  1 69.537 1.1319  0.115  
+ den  1 69.541 1.1287  0.140  
+ cec  1 69.583 1.0912  0.165  
+ wc   1 69.597 1.0778  0.165  
+ fl   1 69.591 1.0840  0.195  
+ sl   1 69.602 1.0735  0.240  
+ tk   1 69.612 1.0651  0.240  
+ nl   1 69.701 0.9853  0.560  
+ ep   1 69.780 0.9145  0.790  
+ ek   1 69.827 0.8727  0.900  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

4.2 获得OTU间生态位距离并与遗传距离矩阵顺序保持一致

env_niche <- wascores(env_norep[,c(1:2,6)],nifhotu_norep)
pH.dist = as.matrix(dist(env_niche[,1]), labels=TRUE)
tn.dist = as.matrix(dist(env_niche[,2]), labels=TRUE)
pH.dist <- pH.dist[colnames(otu_phydist),colnames(otu_phydist)]
tn.dist <- tn.dist[colnames(otu_phydist),colnames(otu_phydist)]

4.3 可视化观察大致趋势

occor.r <- pH.dist
#occor.r <- tn.dist
data1 <- data.frame(cor = c(unlist(occor.r)),phydist=c(unlist(otu_phydist)))
data1 <- data1[!data1$cor==1,]
fac1<-cut(data1$phydist,2000)
data2<-cbind.data.frame(fac1,data1)
library(plyr)
data3<-ddply(data2,.(fac1),colwise(median))
plot(data3$phydist,data3$cor)

4.4 Mantel correlogram检验并输出结果

occor.r[upper.tri(occor.r, diag=TRUE)] = NA
otu_phydist[upper.tri(otu_phydist, diag=TRUE)] = NA
man2 <- mantel.correlog(occor.r,otu_phydist)
write.table(man2$mantel.res,"~/Desktop/abiotic niche to test phylogenetic signal.txt",sep = "\t",quote=FALSE,row.names=TRUE)

5.基于栖息地距离的遗传发育信号检验

5.1 计算栖息地距离并与遗传距离矩阵顺序保持一致

habitat_bray <- as.matrix(vegdist(t(nifhotu_norep), method="bray"))
habitat_bray <- habitat_bray[colnames(otu_phydist),colnames(otu_phydist)]

5.2 可视化观察大致趋势

occor.r <- habitat_bray
#occor.r <- tn.dist
data1 <- data.frame(cor = c(unlist(occor.r)),phydist=c(unlist(otu_phydist)))
data1 <- data1[!data1$cor==1,]
fac1<-cut(data1$phydist,2000)
data2<-cbind.data.frame(fac1,data1)
library(plyr)
data3<-ddply(data2,.(fac1),colwise(median))
plot(data3$phydist,data3$cor)

5.3 Mantel correlogram检验并输出结果

#该步骤耗时较长,建议输出变量保留结果。
occor.r[upper.tri(occor.r, diag=TRUE)] = NA
otu_phydist[upper.tri(otu_phydist, diag=TRUE)] = NA
man2 <- mantel.correlog(occor.r,otu_phydist)
write.table(man2$mantel.res,"~/Desktop/habitat similarity to test phylogenetic signal.txt",sep = "\t",quote=FALSE,row.names=TRUE)

6.基于物种关联矩阵的遗传发育信号检验

6.1 计算物种关联矩阵并与遗传距离矩阵顺序保持一致

fast_spearman_fdr <- function(otu_niche){
  r <- cor(otu_niche,method="spearman")
  n = nrow(otu_niche)
  t <- (r * sqrt(n - 2))/sqrt(1 - r^2)
  p <- -2 * expm1(pt(abs(t), (n - 2), log.p = TRUE))
  p[upper.tri(p, diag = FALSE)] <- p.adjust(p[upper.tri(p,diag = FALSE)], "fdr")
  p[lower.tri(p, diag = FALSE)] = t(p)[lower.tri(p, diag = FALSE)]
  return(list(r=r,p=p))
}
occor <- fast_spearman_fdr(nifhotu_norep)
occor.r <- occor$r
occor.r <- occor.r[colnames(otu_phydist),colnames(otu_phydist)]

6.2 可视化观察大致趋势

data1 <- data.frame(cor = c(unlist(occor.r)),phydist=c(unlist(otu_phydist)))
data1 <- data1[!data1$cor==1,]
fac1<-cut(data1$phydist,2000)
data2<-cbind.data.frame(fac1,data1)
library(plyr)
data3<-ddply(data2,.(fac1),colwise(median))
plot(data3$phydist,data3$cor)

6.3 Mantel correlogram检验并输出结果

#该步骤耗时较长,建议输出变量保留结果。
occor.r[upper.tri(occor.r, diag=TRUE)] = NA
otu_phydist[upper.tri(otu_phydist, diag=TRUE)] = NA
man2 <- mantel.correlog(occor.r,otu_phydist)
write.table(man2$mantel.res,"~/Desktop/habitat similarity to test phylogenetic signal.txt",sep = "\t",quote=FALSE,row.names=TRUE)
LS0tCnRpdGxlOiAi5qOA5rWLT1RV5bqP5YiX6YGX5Lyg5Y+R6IKy5L+h5Y+355qEUuWunueOsCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIyMgMS7liqDovb1S5YyF5ZKM5rWL6K+V5pWw5o2uCmBgYHtyLG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodmVnYW4pCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KHBpY2FudGUpCmxpYnJhcnkodmVnYW4pCm5pZmhvdHVfbm9yZXAgPC0gcmVhZC5kZWxpbSgiLi9kYXRhL25pZmhvdHVfbm9fcmVwcy50eHQiLCByb3cubmFtZXM9MSkKZW52X25vcmVwIDwtIHJlYWQuZGVsaW0oIi4vZGF0YS9lbnZfbm9fcmVwcy50eHQiLCByb3cubmFtZXM9MSkKdHJlZSA8LSByZWFkLnRyZWUoIi4vZGF0YS90cmVlIikKYGBgCgojIyMgMi7orqnmoJHmlofku7bkuI5PVFXooajnm7jljLnphY0KYGBge3J9CnRyZWUkdGlwLmxhYmVsIDwtIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCh0cmVlJHRpcC5sYWJlbCwiJyIsIiIpCnBydW5lX3RyZWU8LXBydW5lLnNhbXBsZShuaWZob3R1X25vcmVwLHRyZWUpCnRpcDwtcHJ1bmVfdHJlZSR0aXAubGFiZWwKY29sbjwtY29sbmFtZXMobmlmaG90dV9ub3JlcCkKbTwtTlVMTApmb3IoaSBpbiAxOmxlbmd0aChjb2xuKSl7CiAgaWYoIWNvbG5baV0laW4ldGlwKXsKICAgIHByaW50KHBhc3RlKCJkZWxldGUgdGhpcyBPVFUgZnJvbSB0cmVlOiIsY29sbltpXSkpCiAgICBtPC1jYmluZChtLGNvbG5baV0pCiAgfQp9Cm08LWFzLnZlY3RvcihtKQpuaWZob3R1X25vcmVwPC1uaWZob3R1X25vcmVwWywhY29sbmFtZXMobmlmaG90dV9ub3JlcCklaW4lbV0KYGBgCgojIyMgMy7ojrflvpdPVFXpl7TpgZfkvKDlj5HogrLot53nprsKYGBge3J9Cm90dV9waHlkaXN0IDwtIGNvcGhlbmV0aWMocHJ1bmVfdHJlZSkKYGBgCgojIyMgNC7ln7rkuo7nlJ/mgIHkvY3ot53nprvnmoTpgZfkvKDlj5HogrLkv6Hlj7fmo4DpqowKIyMjIyA0LjEgUkRB5YiG5p6Q5bm26I635b6X5b2x5ZON5pi+6JGX55qE546v5aKD5Zug5a2QCmBgYHtyfQojZGlzdGFuY2UgY2FsY3VsYXRpb24KYnJheV9kaXN0X25vcmVwIDwtIHZlZ2Rpc3QobmlmaG90dV9ub3JlcCxtZXRob2QgPSAiYnJheSIpCiNyZGEgYW5hbHlzaXMKb3R1X2RicmRhX25vcmVwIDwtIGRicmRhKHNxcnQoYnJheV9kaXN0X25vcmVwKX4uLGRhdGE9ZW52X25vcmVwLGFkZCA9IFRSVUUpCmFub3ZhKG90dV9kYnJkYV9ub3JlcCxwZXJtdXRhdGlvbnMgPSBob3cobnBlcm0gPSA5OTkpKQojZm9yd2FyZCBzZWxlY3Rpb24Kc3RlcF9mb3J3YXJkX25vcmVwIDwtIG9yZGlzdGVwKGRicmRhKHNxcnQoYnJheV9kaXN0X25vcmVwKX4xLGRhdGE9ZW52X25vcmVwLGFkZCA9IFRSVUUpLHNjb3BlID0gZm9ybXVsYShvdHVfZGJyZGFfbm9yZXApLGRpcmVjdGlvbj0iZm9yd2FyZCIpCmBgYAoKIyMjIyA0LjIg6I635b6XT1RV6Ze055Sf5oCB5L2N6Led56a75bm25LiO6YGX5Lyg6Led56a755+p6Zi16aG65bqP5L+d5oyB5LiA6Ie0CmBgYHtyfQplbnZfbmljaGUgPC0gd2FzY29yZXMoZW52X25vcmVwWyxjKDE6Miw2KV0sbmlmaG90dV9ub3JlcCkKcEguZGlzdCA9IGFzLm1hdHJpeChkaXN0KGVudl9uaWNoZVssMV0pLCBsYWJlbHM9VFJVRSkKdG4uZGlzdCA9IGFzLm1hdHJpeChkaXN0KGVudl9uaWNoZVssMl0pLCBsYWJlbHM9VFJVRSkKcEguZGlzdCA8LSBwSC5kaXN0W2NvbG5hbWVzKG90dV9waHlkaXN0KSxjb2xuYW1lcyhvdHVfcGh5ZGlzdCldCnRuLmRpc3QgPC0gdG4uZGlzdFtjb2xuYW1lcyhvdHVfcGh5ZGlzdCksY29sbmFtZXMob3R1X3BoeWRpc3QpXQpgYGAKCgojIyMjIDQuMyDlj6/op4bljJbop4Llr5/lpKfoh7Totovlir8KYGBge3J9Cm9jY29yLnIgPC0gcEguZGlzdAojb2Njb3IuciA8LSB0bi5kaXN0CmRhdGExIDwtIGRhdGEuZnJhbWUoY29yID0gYyh1bmxpc3Qob2Njb3IucikpLHBoeWRpc3Q9Yyh1bmxpc3Qob3R1X3BoeWRpc3QpKSkKZGF0YTEgPC0gZGF0YTFbIWRhdGExJGNvcj09MSxdCmZhYzE8LWN1dChkYXRhMSRwaHlkaXN0LDIwMDApCmRhdGEyPC1jYmluZC5kYXRhLmZyYW1lKGZhYzEsZGF0YTEpCmxpYnJhcnkocGx5cikKZGF0YTM8LWRkcGx5KGRhdGEyLC4oZmFjMSksY29sd2lzZShtZWRpYW4pKQpwbG90KGRhdGEzJHBoeWRpc3QsZGF0YTMkY29yKQpgYGAKCiMjIyMgNC40IE1hbnRlbCBjb3JyZWxvZ3JhbeajgOmqjOW5tui+k+WHuue7k+aenApgYGB7cn0Kb2Njb3Iuclt1cHBlci50cmkob2Njb3IuciwgZGlhZz1UUlVFKV0gPSBOQQpvdHVfcGh5ZGlzdFt1cHBlci50cmkob3R1X3BoeWRpc3QsIGRpYWc9VFJVRSldID0gTkEKbWFuMiA8LSBtYW50ZWwuY29ycmVsb2cob2Njb3IucixvdHVfcGh5ZGlzdCkKd3JpdGUudGFibGUobWFuMiRtYW50ZWwucmVzLCJ+L0Rlc2t0b3AvYWJpb3RpYyBuaWNoZSB0byB0ZXN0IHBoeWxvZ2VuZXRpYyBzaWduYWwudHh0IixzZXAgPSAiXHQiLHF1b3RlPUZBTFNFLHJvdy5uYW1lcz1UUlVFKQpgYGAKCiMjIyA1LuWfuuS6juagluaBr+WcsOi3neemu+eahOmBl+S8oOWPkeiCsuS/oeWPt+ajgOmqjAojIyMjIDUuMSDorqHnrpfmoJbmga/lnLDot53nprvlubbkuI7pgZfkvKDot53nprvnn6npmLXpobrluo/kv53mjIHkuIDoh7QKYGBge3J9CmhhYml0YXRfYnJheSA8LSBhcy5tYXRyaXgodmVnZGlzdCh0KG5pZmhvdHVfbm9yZXApLCBtZXRob2Q9ImJyYXkiKSkKaGFiaXRhdF9icmF5IDwtIGhhYml0YXRfYnJheVtjb2xuYW1lcyhvdHVfcGh5ZGlzdCksY29sbmFtZXMob3R1X3BoeWRpc3QpXQpgYGAKCiMjIyMgNS4yIOWPr+inhuWMluinguWvn+Wkp+iHtOi2i+WKvwpgYGB7cn0Kb2Njb3IuciA8LSBoYWJpdGF0X2JyYXkKI29jY29yLnIgPC0gdG4uZGlzdApkYXRhMSA8LSBkYXRhLmZyYW1lKGNvciA9IGModW5saXN0KG9jY29yLnIpKSxwaHlkaXN0PWModW5saXN0KG90dV9waHlkaXN0KSkpCmRhdGExIDwtIGRhdGExWyFkYXRhMSRjb3I9PTEsXQpmYWMxPC1jdXQoZGF0YTEkcGh5ZGlzdCwyMDAwKQpkYXRhMjwtY2JpbmQuZGF0YS5mcmFtZShmYWMxLGRhdGExKQpsaWJyYXJ5KHBseXIpCmRhdGEzPC1kZHBseShkYXRhMiwuKGZhYzEpLGNvbHdpc2UobWVkaWFuKSkKcGxvdChkYXRhMyRwaHlkaXN0LGRhdGEzJGNvcikKYGBgCgojIyMjIDUuMyBNYW50ZWwgY29ycmVsb2dyYW3mo4DpqozlubbovpPlh7rnu5PmnpwKYGBge3J9CiPor6XmraXpqqTogJfml7bovoPplb/vvIzlu7rorq7ovpPlh7rlj5jph4/kv53nlZnnu5PmnpzjgIIKb2Njb3Iuclt1cHBlci50cmkob2Njb3IuciwgZGlhZz1UUlVFKV0gPSBOQQpvdHVfcGh5ZGlzdFt1cHBlci50cmkob3R1X3BoeWRpc3QsIGRpYWc9VFJVRSldID0gTkEKbWFuMiA8LSBtYW50ZWwuY29ycmVsb2cob2Njb3IucixvdHVfcGh5ZGlzdCkKd3JpdGUudGFibGUobWFuMiRtYW50ZWwucmVzLCJ+L0Rlc2t0b3AvaGFiaXRhdCBzaW1pbGFyaXR5IHRvIHRlc3QgcGh5bG9nZW5ldGljIHNpZ25hbC50eHQiLHNlcCA9ICJcdCIscXVvdGU9RkFMU0Uscm93Lm5hbWVzPVRSVUUpCmBgYAoKIyMjIDYu5Z+65LqO54mp56eN5YWz6IGU55+p6Zi155qE6YGX5Lyg5Y+R6IKy5L+h5Y+35qOA6aqMCiMjIyMgNi4xIOiuoeeul+eJqeenjeWFs+iBlOefqemYteW5tuS4jumBl+S8oOi3neemu+efqemYtemhuuW6j+S/neaMgeS4gOiHtApgYGB7cn0KZmFzdF9zcGVhcm1hbl9mZHIgPC0gZnVuY3Rpb24ob3R1X25pY2hlKXsKICByIDwtIGNvcihvdHVfbmljaGUsbWV0aG9kPSJzcGVhcm1hbiIpCiAgbiA9IG5yb3cob3R1X25pY2hlKQogIHQgPC0gKHIgKiBzcXJ0KG4gLSAyKSkvc3FydCgxIC0gcl4yKQogIHAgPC0gLTIgKiBleHBtMShwdChhYnModCksIChuIC0gMiksIGxvZy5wID0gVFJVRSkpCiAgcFt1cHBlci50cmkocCwgZGlhZyA9IEZBTFNFKV0gPC0gcC5hZGp1c3QocFt1cHBlci50cmkocCxkaWFnID0gRkFMU0UpXSwgImZkciIpCiAgcFtsb3dlci50cmkocCwgZGlhZyA9IEZBTFNFKV0gPSB0KHApW2xvd2VyLnRyaShwLCBkaWFnID0gRkFMU0UpXQogIHJldHVybihsaXN0KHI9cixwPXApKQp9Cm9jY29yIDwtIGZhc3Rfc3BlYXJtYW5fZmRyKG5pZmhvdHVfbm9yZXApCm9jY29yLnIgPC0gb2Njb3IkcgpvY2Nvci5yIDwtIG9jY29yLnJbY29sbmFtZXMob3R1X3BoeWRpc3QpLGNvbG5hbWVzKG90dV9waHlkaXN0KV0KYGBgCgojIyMjIDYuMiDlj6/op4bljJbop4Llr5/lpKfoh7Totovlir8KYGBge3J9CmRhdGExIDwtIGRhdGEuZnJhbWUoY29yID0gYyh1bmxpc3Qob2Njb3IucikpLHBoeWRpc3Q9Yyh1bmxpc3Qob3R1X3BoeWRpc3QpKSkKZGF0YTEgPC0gZGF0YTFbIWRhdGExJGNvcj09MSxdCmZhYzE8LWN1dChkYXRhMSRwaHlkaXN0LDIwMDApCmRhdGEyPC1jYmluZC5kYXRhLmZyYW1lKGZhYzEsZGF0YTEpCmxpYnJhcnkocGx5cikKZGF0YTM8LWRkcGx5KGRhdGEyLC4oZmFjMSksY29sd2lzZShtZWRpYW4pKQpwbG90KGRhdGEzJHBoeWRpc3QsZGF0YTMkY29yKQpgYGAKIyMjIyA2LjMgTWFudGVsIGNvcnJlbG9ncmFt5qOA6aqM5bm26L6T5Ye657uT5p6cCmBgYHtyfQoj6K+l5q2l6aqk6ICX5pe26L6D6ZW/77yM5bu66K6u6L6T5Ye65Y+Y6YeP5L+d55WZ57uT5p6c44CCCm9jY29yLnJbdXBwZXIudHJpKG9jY29yLnIsIGRpYWc9VFJVRSldID0gTkEKb3R1X3BoeWRpc3RbdXBwZXIudHJpKG90dV9waHlkaXN0LCBkaWFnPVRSVUUpXSA9IE5BCm1hbjIgPC0gbWFudGVsLmNvcnJlbG9nKG9jY29yLnIsb3R1X3BoeWRpc3QpCndyaXRlLnRhYmxlKG1hbjIkbWFudGVsLnJlcywifi9EZXNrdG9wL2hhYml0YXQgc2ltaWxhcml0eSB0byB0ZXN0IHBoeWxvZ2VuZXRpYyBzaWduYWwudHh0IixzZXAgPSAiXHQiLHF1b3RlPUZBTFNFLHJvdy5uYW1lcz1UUlVFKQpgYGA=