annotate galaxy/stat_anova/abims_anova.r @ 8:c2be3b890724 draft

planemo upload commit 00a7f9aadf30a7d728eb4df72ca38ebe5dd7be03
author lecorguille
date Tue, 06 Jun 2017 09:43:23 -0400
parents b6298c38e53f
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
1 #!/usr/local/public/bin/Rscript
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
2 # version="1.1"
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
3
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
4 # date: 06-06-2012
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
5 # update: 18-02-2014
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
6 # **Authors** Gildas Le Corguille ABiMS - UPMC/CNRS - Station Biologique de Roscoff - gildas.lecorguille|at|sb-roscoff.fr
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
7
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
8 # abims_anova.r version 20140218
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
9
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
10 library(batch)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
11
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
12
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
13 # function avova
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
14 anova = function (file, sampleinfo, mode="column", condition=1, interaction=F, method="BH", threshold=0.01, selection_method="intersection", sep=";", dec=".", outputdatapvalue="anova.data.output", outputdatafiltered="anova.datafiltered.output") {
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
15
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
16
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
17 if (sep=="tabulation") sep="\t"
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
18 if (sep=="semicolon") sep=";"
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
19 if (sep=="comma") sep=","
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
20
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
21 anova_formula_operator = "+"
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
22 if (interaction) anova_formula_operator = "*"
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
23
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
24 # -- import --
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
25 data=read.table(file, header = TRUE, row.names=1, sep = sep, quote="\"", dec = dec, fill = TRUE, comment.char="",na.strings = "NA")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
26
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
27 if (mode == "row") data=t(data)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
28
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
29 sampleinfoTab=read.table(sampleinfo, header = TRUE, row.names=1, sep = sep, quote="\"")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
30 rownames(sampleinfoTab) = make.names(rownames(sampleinfoTab))
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
31
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
32
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
33 # -- group --
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
34 match_data_sampleinfoTab = match(rownames(data),rownames(sampleinfoTab))
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
35 if (sum(is.na(match_data_sampleinfoTab)) > 0) {
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
36 write("ERROR: There is a problem during to match sample names from the data matrix and from the sample info (presence of NA).", stderr())
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
37 write("You may need to use change the mode (column/row)", stderr())
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
38 write("10 first sample names in the data matrix:", stderr())
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
39 write(head(colnames(data)), stderr())
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
40 write("10 first sample names in the sample info:", stderr())
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
41 write(head(rownames(sampleinfoTab)), stderr())
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
42 quit("no",status=10)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
43 }
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
44
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
45
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
46 # -- anova --
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
47
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
48 # formula
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
49 grps=list()
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
50 anova_formula_s = "data ~ "
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
51 cat("\ncontrasts:\n")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
52 for (i in 1:length(condition)) {
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
53 grps[[i]] = factor(sampleinfoTab[,condition[i]][match_data_sampleinfoTab])
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
54 anova_formula_s = paste(anova_formula_s, "grps[[",i,"]]",anova_formula_operator, sep="")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
55 cat(condition[i],"\t",levels(grps[[i]]),"\n")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
56 # write("Current groups: ", stderr())
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
57 # write(grp[[i]], stderr())
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
58 }
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
59 anova_formula_s = substr(anova_formula_s, 1, nchar(anova_formula_s)-1)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
60 anova_formula = as.formula(anova_formula_s)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
61
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
62
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
63
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
64 # anova
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
65 manovaObjectList = manova(anova_formula)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
66 manovaList = summary.aov(manovaObjectList)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
67
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
68 # condition renaming
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
69 manovaRownames = gsub(" ","",rownames(manovaList[[1]]))
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
70 manovaNbrPvalue = length(manovaRownames)-1
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
71 manovaRownames = manovaRownames[-(manovaNbrPvalue+1)]
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
72
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
73 for (i in 1:length(condition)) {
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
74 manovaRownames = sub(paste("grps\\[\\[",i,"\\]\\]",sep=""),condition[i],manovaRownames)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
75 anova_formula_s = sub(paste("grps\\[\\[",i,"\\]\\]",sep=""),condition[i],anova_formula_s)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
76 }
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
77
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
78 # log
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
79 cat("\nanova_formula",anova_formula_s,"\n")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
80
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
81 # p-value
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
82 aovPValue = sapply(manovaList,function(x){x[-(manovaNbrPvalue+1),5]})
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
83 if(length(condition) == 1) aovPValue = t(aovPValue)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
84 rownames(aovPValue) = paste("pvalue_",manovaRownames,sep="")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
85
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
86 # p-value adjusted
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
87 if(length(condition) == 1) {
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
88 aovAdjPValue = t(p.adjust(aovPValue,method=method))
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
89 } else {
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
90 aovAdjPValue = apply(aovPValue,2,p.adjust, method=method)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
91 }
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
92 rownames(aovAdjPValue) = paste("pvalueadjusted.",method,".",manovaRownames,sep="")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
93
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
94 # selection
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
95 colSumThreshold = colSums(aovAdjPValue <= threshold)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
96 if (selection_method == "intersection") {
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
97 datafiltered = data[,colSumThreshold == nrow(aovAdjPValue )]
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
98 } else {
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
99 datafiltered = data[,colSumThreshold != 0]
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
100 }
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
101
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
102 #data=rbind(data, aovPValue, aovAdjPValue)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
103 data=rbind(data, aovAdjPValue)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
104
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
105
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
106 if (mode == "row") {
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
107 data=t(data)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
108 datafiltered=t(datafiltered)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
109 }
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
110
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
111 # -- output / return --
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
112 write.table(data, outputdatapvalue, sep=sep, quote=F, col.names = NA)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
113 write.table(datafiltered, outputdatafiltered, sep=sep, quote=F, col.names = NA)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
114
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
115 # log
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
116 cat("\nthreshold:",threshold,"\n")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
117 cat("result:",nrow(datafiltered),"/",nrow(data),"\n")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
118
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
119 quit("no",status=0)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
120 }
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
121
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
122 # log
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
123 cat("ANOVA\n\n")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
124 cat("Arguments\n")
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
125 args <- commandArgs(trailingOnly = TRUE)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
126 print(args)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
127
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
128 listArguments = parseCommandArgs(evaluate=FALSE)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
129 do.call(anova, listArguments)
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
130
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
131
b6298c38e53f planemo upload commit b931b0c4ca182ea28a9ed1365bece9b2326fd64c
lecorguille
parents:
diff changeset
132