- Timestamp:
- 03/18/11 07:27:00 (13 years ago)
- Location:
- branches/DataAnalysis Refactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4
- Files:
-
- 2 deleted
- 1 edited
- 3 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/DataAnalysis Refactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionLatexFormatter.cs
r5735 r5745 25 25 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; 26 26 using System.Collections.Generic; 27 using HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols;28 27 using System; 29 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbols;30 28 using HeuristicLab.Core; 31 29 using HeuristicLab.Common; 32 30 33 namespace HeuristicLab.Problems.DataAnalysis.Symbolic .Formatters{31 namespace HeuristicLab.Problems.DataAnalysis.Symbolic { 34 32 [Item("LaTeX String Formatter", "Formatter for symbolic expression trees for import into LaTeX documents.")] 35 33 [StorableClass] 36 public sealed class Symbolic ExpressionTreeLatexFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {34 public sealed class SymbolicDataAnalysisExpressionLatexFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter { 37 35 private List<double> constants; 38 36 private int currentLag; 39 37 40 38 [StorableConstructor] 41 private Symbolic ExpressionTreeLatexFormatter(bool deserializing) : base(deserializing) { }42 private Symbolic ExpressionTreeLatexFormatter(SymbolicExpressionTreeLatexFormatter original, Cloner cloner)39 private SymbolicDataAnalysisExpressionLatexFormatter(bool deserializing) : base(deserializing) { } 40 private SymbolicDataAnalysisExpressionLatexFormatter(SymbolicDataAnalysisExpressionLatexFormatter original, Cloner cloner) 43 41 : base(original, cloner) { 44 42 constants = new List<double>(original.constants); 45 43 } 46 public SymbolicExpressionTreeLatexFormatter() 47 : base("LaTeX String Formatter", "Formatter for symbolic expression trees for import into LaTeX documents.") { 44 public SymbolicDataAnalysisExpressionLatexFormatter() 45 : base() { 46 Name = ItemName; 47 Description = ItemDescription; 48 48 constants = new List<double>(); 49 49 } 50 50 51 51 public override IDeepCloneable Clone(Cloner cloner) { 52 return new Symbolic ExpressionTreeLatexFormatter(this, cloner);53 } 54 55 public string Format( SymbolicExpressionTree symbolicExpressionTree) {52 return new SymbolicDataAnalysisExpressionLatexFormatter(this, cloner); 53 } 54 55 public string Format(ISymbolicExpressionTree symbolicExpressionTree) { 56 56 try { 57 57 StringBuilder strBuilder = new StringBuilder(); … … 68 68 } 69 69 70 private string FormatRecursively( SymbolicExpressionTreeNode node) {70 private string FormatRecursively(ISymbolicExpressionTreeNode node) { 71 71 StringBuilder strBuilder = new StringBuilder(); 72 72 currentLag = 0; 73 73 FormatBegin(node, strBuilder); 74 74 75 if (node.Sub Trees.Count > 0) {76 strBuilder.Append(FormatRecursively(node. SubTrees[0]));77 } 78 foreach (SymbolicExpressionTreeNode subTree in node.Sub Trees.Skip(1)) {75 if (node.SubtreesCount > 0) { 76 strBuilder.Append(FormatRecursively(node.GetSubtree(0))); 77 } 78 foreach (SymbolicExpressionTreeNode subTree in node.Subtrees.Skip(1)) { 79 79 FormatSep(node, strBuilder); 80 80 // format the whole subtree … … 87 87 } 88 88 89 private void FormatBegin( SymbolicExpressionTreeNode node, StringBuilder strBuilder) {89 private void FormatBegin(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) { 90 90 if (node.Symbol is Addition) { 91 91 strBuilder.Append(@" \left( "); 92 92 } else if (node.Symbol is Subtraction) { 93 if (node.Sub Trees.Count == 1) {93 if (node.SubtreesCount == 1) { 94 94 strBuilder.Append(@"- \left("); 95 95 } else { … … 98 98 } else if (node.Symbol is Multiplication) { 99 99 } else if (node.Symbol is Division) { 100 if (node.Sub Trees.Count == 1) {100 if (node.SubtreesCount == 1) { 101 101 strBuilder.Append(@" \cfrac{1}{"); 102 102 } else { … … 105 105 } else if (node.Symbol is Average) { 106 106 // skip output of (1/1) if only one subtree 107 if (node.Sub Trees.Count > 1) {108 strBuilder.Append(@" \cfrac{1}{" + node.Sub Trees.Count + @"}");107 if (node.SubtreesCount > 1) { 108 strBuilder.Append(@" \cfrac{1}{" + node.SubtreesCount + @"}"); 109 109 } 110 110 strBuilder.Append(@" \left("); … … 128 128 strBuilder.Append(@" \left( \left( "); 129 129 } else if (node.Symbol is Not) { 130 strBuilder.Append(@" -1.0 \cdot\left( ");130 strBuilder.Append(@" \neg \left( "); 131 131 } else if (node.Symbol is IfThenElse) { 132 132 strBuilder.Append(@"\left( \operatorname{if} \left( 0 < "); … … 140 140 strBuilder.Append(LagToString(currentLag + laggedVarNode.Lag)); 141 141 constants.Add(laggedVarNode.Weight); 142 } else if (node.Symbol is HeuristicLab.Problems.DataAnalysis.Symbolic. Symbols.Variable) {142 } else if (node.Symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Variable) { 143 143 var varNode = node as VariableTreeNode; 144 144 strBuilder.Append("c_{" + constants.Count + "} " + varNode.VariableName); … … 182 182 } 183 183 184 private void FormatSep( SymbolicExpressionTreeNode node, StringBuilder strBuilder) {184 private void FormatSep(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) { 185 185 if (node.Symbol is Addition) { 186 186 strBuilder.Append(" + "); … … 238 238 } 239 239 240 private void FormatEnd( SymbolicExpressionTreeNode node, StringBuilder strBuilder) {240 private void FormatEnd(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) { 241 241 if (node.Symbol is Addition) { 242 242 strBuilder.Append(@" \right) "); … … 246 246 } else if (node.Symbol is Division) { 247 247 strBuilder.Append("} "); 248 if (node.Sub Trees.Count > 1)248 if (node.SubtreesCount > 1) 249 249 strBuilder.Append("{1} "); 250 for (int i = 1; i < node.Sub Trees.Count; i++) {250 for (int i = 1; i < node.SubtreesCount; i++) { 251 251 strBuilder.Append(" } "); 252 252 } … … 277 277 } else if (node.Symbol is Constant) { 278 278 } else if (node.Symbol is LaggedVariable) { 279 } else if (node.Symbol is HeuristicLab.Problems.DataAnalysis.Symbolic. Symbols.Variable) {279 } else if (node.Symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Variable) { 280 280 } else if (node.Symbol is ProgramRootSymbol) { 281 281 // output all constant values -
branches/DataAnalysis Refactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionMATLABFormatter.cs
r5735 r5745 25 25 using HeuristicLab.Common; 26 26 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; 27 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbols;28 using HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols;29 27 using HeuristicLab.Problems.DataAnalysis; 30 using HeuristicLab.Problems.DataAnalysis.Symbolic.Formatters;31 28 using System.Collections.Generic; 32 29 using System; 33 30 using System.Globalization; 34 35 namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Formatters { 36 37 [Item("SymbolicExpressionTreeMATLABFormatter", "String formatter for string representations of symbolic expression trees in MATLAB syntax.")] 31 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; 32 33 namespace HeuristicLab.Problems.DataAnalysis.Symbolic { 34 35 [Item("MATLAB String Formatter", "String formatter for string representations of symbolic data analysis expressions in MATLAB syntax.")] 38 36 [StorableClass] 39 public sealed class Symbolic ExpressionTreeMATLABFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {37 public sealed class SymbolicDataAnalysisExpressionMATLABFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter { 40 38 private int currentLag; 41 39 42 40 [StorableConstructor] 43 private Symbolic ExpressionTreeMATLABFormatter(bool deserializing) : base(deserializing) { }44 private Symbolic ExpressionTreeMATLABFormatter(SymbolicExpressionTreeMATLABFormatter original, Cloner cloner) : base(original, cloner) { }45 public Symbolic ExpressionTreeMATLABFormatter()41 private SymbolicDataAnalysisExpressionMATLABFormatter(bool deserializing) : base(deserializing) { } 42 private SymbolicDataAnalysisExpressionMATLABFormatter(SymbolicDataAnalysisExpressionMATLABFormatter original, Cloner cloner) : base(original, cloner) { } 43 public SymbolicDataAnalysisExpressionMATLABFormatter() 46 44 : base() { 47 Name = "MATLAB String Formatter"; 45 Name = ItemName; 46 Description = ItemDescription; 48 47 } 49 48 public override IDeepCloneable Clone(Cloner cloner) { 50 return new Symbolic ExpressionTreeMATLABFormatter(this, cloner);49 return new SymbolicDataAnalysisExpressionMATLABFormatter(this, cloner); 51 50 } 52 51 private int currentIndexNumber; … … 65 64 } 66 65 67 public string Format( SymbolicExpressionTree symbolicExpressionTree) {66 public string Format(ISymbolicExpressionTree symbolicExpressionTree) { 68 67 currentLag = 0; 69 68 currentIndexNumber = 0; … … 71 70 } 72 71 73 private string FormatRecursively( SymbolicExpressionTreeNode node) {74 Symbol symbol = node.Symbol;72 private string FormatRecursively(ISymbolicExpressionTreeNode node) { 73 ISymbol symbol = node.Symbol; 75 74 StringBuilder stringBuilder = new StringBuilder(); 76 75 … … 84 83 foreach (string variableName in variableNames) 85 84 stringBuilder.AppendLine(" " + variableName + " = Data(:, ???);"); 86 stringBuilder.AppendLine(" for " +CurrentIndexVariable+" = size(Data,1):-1:1");87 stringBuilder.AppendLine(" Target_estimated(" +CurrentIndexVariable+") = " + FormatRecursively(node.SubTrees[0]) + ";");85 stringBuilder.AppendLine(" for " + CurrentIndexVariable + " = size(Data,1):-1:1"); 86 stringBuilder.AppendLine(" Target_estimated(" + CurrentIndexVariable + ") = " + FormatRecursively(node.GetSubtree(0)) + ";"); 88 87 stringBuilder.AppendLine(" end"); 89 88 stringBuilder.AppendLine("end"); … … 102 101 103 102 if (symbol is StartSymbol) 104 return FormatRecursively(node. SubTrees[0]);103 return FormatRecursively(node.GetSubtree(0)); 105 104 106 105 stringBuilder.Append("("); 107 106 108 107 if (symbol is Addition) { 109 for (int i = 0; i < node.Sub Trees.Count; i++) {108 for (int i = 0; i < node.SubtreesCount; i++) { 110 109 if (i > 0) stringBuilder.Append("+"); 111 stringBuilder.Append(FormatRecursively(node. SubTrees[i]));110 stringBuilder.Append(FormatRecursively(node.GetSubtree(i))); 112 111 } 113 112 } else if (symbol is And) { 114 113 stringBuilder.Append("(("); 115 for (int i = 0; i < node.Sub Trees.Count; i++) {114 for (int i = 0; i < node.SubtreesCount; i++) { 116 115 if (i > 0) stringBuilder.Append("&"); 117 116 stringBuilder.Append("(("); 118 stringBuilder.Append(FormatRecursively(node. SubTrees[i]));117 stringBuilder.Append(FormatRecursively(node.GetSubtree(i))); 119 118 stringBuilder.Append(")>0)"); 120 119 } … … 122 121 } else if (symbol is Average) { 123 122 stringBuilder.Append("(1/"); 124 stringBuilder.Append(node.Sub Trees.Count);123 stringBuilder.Append(node.SubtreesCount); 125 124 stringBuilder.Append(")*("); 126 for (int i = 0; i < node.Sub Trees.Count; i++) {125 for (int i = 0; i < node.SubtreesCount; i++) { 127 126 if (i > 0) stringBuilder.Append("+"); 128 127 stringBuilder.Append("("); 129 stringBuilder.Append(FormatRecursively(node. SubTrees[i]));128 stringBuilder.Append(FormatRecursively(node.GetSubtree(i))); 130 129 stringBuilder.Append(")"); 131 130 } … … 136 135 } else if (symbol is Cosine) { 137 136 stringBuilder.Append("cos("); 138 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));137 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 139 138 stringBuilder.Append(")"); 140 139 } else if (symbol is Division) { 141 if (node.Sub Trees.Count == 1) {140 if (node.SubtreesCount == 1) { 142 141 stringBuilder.Append("1/"); 143 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));142 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 144 143 } else { 145 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));144 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 146 145 stringBuilder.Append("/("); 147 for (int i = 1; i < node.Sub Trees.Count; i++) {146 for (int i = 1; i < node.SubtreesCount; i++) { 148 147 if (i > 1) stringBuilder.Append("*"); 149 stringBuilder.Append(FormatRecursively(node. SubTrees[i]));148 stringBuilder.Append(FormatRecursively(node.GetSubtree(i))); 150 149 } 151 150 stringBuilder.Append(")"); … … 153 152 } else if (symbol is Exponential) { 154 153 stringBuilder.Append("exp("); 155 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));154 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 156 155 stringBuilder.Append(")"); 157 156 } else if (symbol is GreaterThan) { 158 157 stringBuilder.Append("(("); 159 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));158 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 160 159 stringBuilder.Append(">"); 161 stringBuilder.Append(FormatRecursively(node. SubTrees[1]));160 stringBuilder.Append(FormatRecursively(node.GetSubtree(1))); 162 161 stringBuilder.Append(")-0.5)*2"); // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp. 163 162 } else if (symbol is IfThenElse) { 164 163 stringBuilder.Append("("); 165 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));164 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 166 165 stringBuilder.Append(">0)*"); 167 stringBuilder.Append(FormatRecursively(node. SubTrees[1]));166 stringBuilder.Append(FormatRecursively(node.GetSubtree(1))); 168 167 stringBuilder.Append("+"); 169 168 stringBuilder.Append("("); 170 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));169 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 171 170 stringBuilder.Append("<=0)*"); 172 stringBuilder.Append(FormatRecursively(node. SubTrees[2]));171 stringBuilder.Append(FormatRecursively(node.GetSubtree(2))); 173 172 } else if (symbol is LaggedVariable) { 174 173 // this if must be checked before if(symbol is LaggedVariable) … … 179 178 } else if (symbol is LessThan) { 180 179 stringBuilder.Append("(("); 181 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));180 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 182 181 stringBuilder.Append("<"); 183 stringBuilder.Append(FormatRecursively(node. SubTrees[1]));182 stringBuilder.Append(FormatRecursively(node.GetSubtree(1))); 184 183 stringBuilder.Append(")-0.5)*2"); // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp. 185 184 } else if (symbol is Logarithm) { 186 185 stringBuilder.Append("log_("); 187 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));186 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 188 187 stringBuilder.Append(")"); 189 188 } else if (symbol is Multiplication) { 190 for (int i = 0; i < node.Sub Trees.Count; i++) {189 for (int i = 0; i < node.SubtreesCount; i++) { 191 190 if (i > 0) stringBuilder.Append("*"); 192 stringBuilder.Append(FormatRecursively(node. SubTrees[i]));191 stringBuilder.Append(FormatRecursively(node.GetSubtree(i))); 193 192 } 194 193 } else if (symbol is Not) { 195 stringBuilder.Append(FormatRecursively(node.SubTrees[0])); 196 stringBuilder.Append("*-1"); 194 stringBuilder.Append("~("); 195 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 196 stringBuilder.Append(" > 0 )"); 197 197 } else if (symbol is Or) { 198 198 stringBuilder.Append("(("); 199 for (int i = 0; i < node.Sub Trees.Count; i++) {199 for (int i = 0; i < node.SubtreesCount; i++) { 200 200 if (i > 0) stringBuilder.Append("|"); 201 201 stringBuilder.Append("(("); 202 stringBuilder.Append(FormatRecursively(node. SubTrees[i]));202 stringBuilder.Append(FormatRecursively(node.GetSubtree(i))); 203 203 stringBuilder.Append(")>0)"); 204 204 } … … 206 206 } else if (symbol is Sine) { 207 207 stringBuilder.Append("sin("); 208 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));208 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 209 209 stringBuilder.Append(")"); 210 210 } else if (symbol is Subtraction) { 211 if (node.Sub Trees.Count == 1) {211 if (node.SubtreesCount == 1) { 212 212 stringBuilder.Append("-1*"); 213 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));213 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 214 214 } else { 215 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));216 for (int i = 1; i < node.Sub Trees.Count; i++) {215 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 216 for (int i = 1; i < node.SubtreesCount; i++) { 217 217 stringBuilder.Append("-"); 218 stringBuilder.Append(FormatRecursively(node. SubTrees[i]));218 stringBuilder.Append(FormatRecursively(node.GetSubtree(i))); 219 219 } 220 220 } 221 221 } else if (symbol is Tangent) { 222 222 stringBuilder.Append("tan("); 223 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));224 stringBuilder.Append(")"); 225 } else if (symbol is HeuristicLab.Problems.DataAnalysis.Symbolic. Symbols.Variable) {223 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 224 stringBuilder.Append(")"); 225 } else if (symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Variable) { 226 226 VariableTreeNode variableTreeNode = node as VariableTreeNode; 227 227 stringBuilder.Append(variableTreeNode.Weight.ToString(CultureInfo.InvariantCulture)); … … 230 230 } else if (symbol is Power) { 231 231 stringBuilder.Append("("); 232 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));232 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 233 233 stringBuilder.Append(")^round("); 234 stringBuilder.Append(FormatRecursively(node. SubTrees[1]));234 stringBuilder.Append(FormatRecursively(node.GetSubtree(1))); 235 235 stringBuilder.Append(")"); 236 236 } else if (symbol is Root) { 237 237 stringBuilder.Append("("); 238 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));238 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 239 239 stringBuilder.Append(")^(1 / round("); 240 stringBuilder.Append(FormatRecursively(node. SubTrees[1]));240 stringBuilder.Append(FormatRecursively(node.GetSubtree(1))); 241 241 stringBuilder.Append("))"); 242 242 } else if (symbol is Derivative) { 243 243 stringBuilder.Append("fivePoint("); 244 244 // f0 245 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));245 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 246 246 stringBuilder.Append(", "); 247 247 // f1 248 248 currentLag--; 249 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));249 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 250 250 stringBuilder.Append(", "); 251 251 // f3 252 252 currentLag -= 2; 253 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));253 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 254 254 stringBuilder.Append(", "); 255 255 currentLag--; 256 256 // f4 257 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));257 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 258 258 stringBuilder.Append(")"); 259 259 currentLag += 4; … … 262 262 string prevCounterVariable = CurrentIndexVariable; 263 263 string counterVariable = AllocateIndexVariable(); 264 stringBuilder.AppendLine(" sum (map(@(" + counterVariable + ") " + FormatRecursively(node. SubTrees[0]) + ", (" + prevCounterVariable + "+" + laggedNode.Lag + "):" + prevCounterVariable + "))");264 stringBuilder.AppendLine(" sum (map(@(" + counterVariable + ") " + FormatRecursively(node.GetSubtree(0)) + ", (" + prevCounterVariable + "+" + laggedNode.Lag + "):" + prevCounterVariable + "))"); 265 265 ReleaseIndexVariable(); 266 266 } else if (symbol is TimeLag) { 267 267 var laggedNode = node as LaggedTreeNode; 268 268 currentLag += laggedNode.Lag; 269 stringBuilder.Append(FormatRecursively(node. SubTrees[0]));269 stringBuilder.Append(FormatRecursively(node.GetSubtree(0))); 270 270 currentLag -= laggedNode.Lag; 271 271 } else { -
branches/DataAnalysis Refactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
r5733 r5745 119 119 </Compile> 120 120 <Compile Include="Analyzers\SymbolicDataAnalysisVariableFrequencyAnalyzer.cs" /> 121 <Compile Include="Formatters\SymbolicDataAnalysisExpressionLatexFormatter.cs" /> 122 <Compile Include="Formatters\SymbolicDataAnalysisExpressionMATLABFormatter.cs" /> 121 123 <Compile Include="Interfaces\ISymbolicDataAnalysisBoundedOperator.cs" /> 122 124 <Compile Include="Interfaces\ISymbolicDataAnalysisExpressionTreeInterpreter.cs" />
Note: See TracChangeset
for help on using the changeset viewer.