Changeset 17439


Ignore:
Timestamp:
02/17/20 15:13:17 (2 years ago)
Author:
dpiringe
Message:

#3026:

  • fixed a bug in HeuristicLab.JsonInterface.App -> now the Runner checks if the instantiated optimizer is an EngineAlgorithm, if true: Engine = SequentialEngine (engine can be configured in later versions)
  • added a TabControl in ExportJsonDialog for parameters and results
  • updated parameter tree view with checkboxes (and linked them with VM)
  • renamed ActivatedResults to Results for templates
  • fixed a bug with injection of operators in MultiCheckedOperatorConverter -> now operators of an ValueParameter get set correctly
  • updated MultiCheckedOperatorConverter to extract/inject parameters of operators
  • fixed bug with path for template -> removed usage of method Path.GetDirectoryName, returned wrong results
  • splitted cache for JsonItemConverter into a cache for injection and extraction
  • JsonTemplateInstantiator now uses first item in objects array instead of searching for an object with template name
Location:
branches/3026_IntegrationIntoSymSpace
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface.App/HeuristicLab.JsonInterface.App.csproj

    r17324 r17439  
    8383      <Name>HeuristicLab.Problems.Instances-3.3</Name>
    8484    </ProjectReference>
     85    <ProjectReference Include="..\HeuristicLab.SequentialEngine\3.3\HeuristicLab.SequentialEngine-3.3.csproj">
     86      <Project>{DC3D7072-7999-4719-B65D-3997744D5DC1}</Project>
     87      <Name>HeuristicLab.SequentialEngine-3.3</Name>
     88    </ProjectReference>
    8589  </ItemGroup>
    8690  <ItemGroup />
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface.App/Runner.cs

    r17395 r17439  
    77using System.Threading.Tasks;
    88using HeuristicLab.Optimization;
     9using HeuristicLab.SequentialEngine;
    910
    1011namespace HeuristicLab.JsonInterface.App {
     
    1213    internal static void Run(string template, string config, string outputFile = @"C:\Workspace\test.txt") {
    1314      IOptimizer optimizer = JsonTemplateInstantiator.Instantiate(template, config);
    14  
     15      if(optimizer is EngineAlgorithm e)
     16        e.Engine = new SequentialEngine.SequentialEngine();
     17     
    1518      Task task = optimizer.StartAsync();
    1619      while(!task.IsCompleted) {
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface.OptimizerIntegration/ViewModels/JsonItemVMBase.cs

    r17433 r17439  
    4242      set {
    4343        selected = value;
    44         if(TreeNode != null)
     44        if(TreeNode != null) {
    4545          TreeNode.ForeColor = (selected ? Color.Black : Color.Red);
     46          TreeNode.Checked = value;
     47        }
    4648        if (TreeView != null)
    4749          TreeView.Refresh();
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface.OptimizerIntegration/Views/ExportJsonDialog.Designer.cs

    r17435 r17439  
    3030      this.groupBoxDetails = new System.Windows.Forms.GroupBox();
    3131      this.panel = new System.Windows.Forms.Panel();
    32       this.jsonItemBindingSource = new System.Windows.Forms.BindingSource(this.components);
    3332      this.resultItems = new System.Windows.Forms.CheckedListBox();
    3433      this.groupBox2 = new System.Windows.Forms.GroupBox();
    3534      this.groupBox3 = new System.Windows.Forms.GroupBox();
    36       this.splitContainer1 = new System.Windows.Forms.SplitContainer();
    3735      this.splitContainer2 = new System.Windows.Forms.SplitContainer();
     36      this.tabControl1 = new System.Windows.Forms.TabControl();
     37      this.tabPage1 = new System.Windows.Forms.TabPage();
     38      this.tabPage2 = new System.Windows.Forms.TabPage();
     39      this.jsonItemBindingSource = new System.Windows.Forms.BindingSource(this.components);
    3840      this.groupBoxDetails.SuspendLayout();
    39       ((System.ComponentModel.ISupportInitialize)(this.jsonItemBindingSource)).BeginInit();
    4041      this.groupBox2.SuspendLayout();
    4142      this.groupBox3.SuspendLayout();
    42       ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
    43       this.splitContainer1.Panel1.SuspendLayout();
    44       this.splitContainer1.Panel2.SuspendLayout();
    45       this.splitContainer1.SuspendLayout();
    4643      ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit();
    4744      this.splitContainer2.Panel1.SuspendLayout();
    4845      this.splitContainer2.Panel2.SuspendLayout();
    4946      this.splitContainer2.SuspendLayout();
     47      this.tabControl1.SuspendLayout();
     48      this.tabPage1.SuspendLayout();
     49      this.tabPage2.SuspendLayout();
     50      ((System.ComponentModel.ISupportInitialize)(this.jsonItemBindingSource)).BeginInit();
    5051      this.SuspendLayout();
    5152      //
     
    6061      this.exportButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
    6162            | System.Windows.Forms.AnchorStyles.Right)));
    62       this.exportButton.Location = new System.Drawing.Point(3, 570);
     63      this.exportButton.Location = new System.Drawing.Point(591, 578);
    6364      this.exportButton.Name = "exportButton";
    64       this.exportButton.Size = new System.Drawing.Size(422, 29);
     65      this.exportButton.Size = new System.Drawing.Size(229, 29);
    6566      this.exportButton.TabIndex = 1;
    6667      this.exportButton.Text = "Export";
     
    7374            | System.Windows.Forms.AnchorStyles.Left)
    7475            | System.Windows.Forms.AnchorStyles.Right)));
     76      this.treeView.CheckBoxes = true;
    7577      this.treeView.Location = new System.Drawing.Point(6, 19);
    7678      this.treeView.Name = "treeView";
    77       this.treeView.Size = new System.Drawing.Size(353, 327);
     79      this.treeView.Size = new System.Drawing.Size(352, 497);
    7880      this.treeView.TabIndex = 3;
    7981      this.treeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView_AfterSelect);
     
    8587            | System.Windows.Forms.AnchorStyles.Right)));
    8688      this.groupBoxDetails.Controls.Add(this.panel);
    87       this.groupBoxDetails.Location = new System.Drawing.Point(3, 3);
     89      this.groupBoxDetails.Location = new System.Drawing.Point(3, 0);
    8890      this.groupBoxDetails.Name = "groupBoxDetails";
    89       this.groupBoxDetails.Size = new System.Drawing.Size(422, 561);
     91      this.groupBoxDetails.Size = new System.Drawing.Size(415, 522);
    9092      this.groupBoxDetails.TabIndex = 4;
    9193      this.groupBoxDetails.TabStop = false;
     
    100102      this.panel.Location = new System.Drawing.Point(7, 20);
    101103      this.panel.Name = "panel";
    102       this.panel.Size = new System.Drawing.Size(409, 535);
     104      this.panel.Size = new System.Drawing.Size(402, 496);
    103105      this.panel.TabIndex = 0;
    104       //
    105       // jsonItemBindingSource
    106       //
    107       this.jsonItemBindingSource.DataSource = typeof(HeuristicLab.JsonInterface.IJsonItem);
    108106      //
    109107      // resultItems
     
    115113      this.resultItems.Location = new System.Drawing.Point(6, 19);
    116114      this.resultItems.Name = "resultItems";
    117       this.resultItems.Size = new System.Drawing.Size(353, 199);
     115      this.resultItems.Size = new System.Drawing.Size(777, 499);
    118116      this.resultItems.TabIndex = 5;
    119117      //
     
    124122            | System.Windows.Forms.AnchorStyles.Right)));
    125123      this.groupBox2.Controls.Add(this.treeView);
    126       this.groupBox2.Location = new System.Drawing.Point(3, 3);
     124      this.groupBox2.Location = new System.Drawing.Point(0, 0);
    127125      this.groupBox2.Name = "groupBox2";
    128       this.groupBox2.Size = new System.Drawing.Size(365, 352);
     126      this.groupBox2.Size = new System.Drawing.Size(364, 522);
    129127      this.groupBox2.TabIndex = 6;
    130128      this.groupBox2.TabStop = false;
     
    137135            | System.Windows.Forms.AnchorStyles.Right)));
    138136      this.groupBox3.Controls.Add(this.resultItems);
    139       this.groupBox3.Location = new System.Drawing.Point(3, 3);
     137      this.groupBox3.Location = new System.Drawing.Point(6, 6);
    140138      this.groupBox3.Name = "groupBox3";
    141       this.groupBox3.Size = new System.Drawing.Size(365, 231);
     139      this.groupBox3.Size = new System.Drawing.Size(789, 522);
    142140      this.groupBox3.TabIndex = 7;
    143141      this.groupBox3.TabStop = false;
    144142      this.groupBox3.Text = "Result Elements";
    145143      //
    146       // splitContainer1
    147       //
    148       this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
    149             | System.Windows.Forms.AnchorStyles.Left)
    150             | System.Windows.Forms.AnchorStyles.Right)));
    151       this.splitContainer1.Location = new System.Drawing.Point(3, 3);
    152       this.splitContainer1.Name = "splitContainer1";
    153       this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
    154       //
    155       // splitContainer1.Panel1
    156       //
    157       this.splitContainer1.Panel1.Controls.Add(this.groupBox2);
    158       //
    159       // splitContainer1.Panel2
    160       //
    161       this.splitContainer1.Panel2.Controls.Add(this.groupBox3);
    162       this.splitContainer1.Size = new System.Drawing.Size(371, 599);
    163       this.splitContainer1.SplitterDistance = 358;
    164       this.splitContainer1.TabIndex = 8;
    165       //
    166144      // splitContainer2
    167145      //
     
    169147            | System.Windows.Forms.AnchorStyles.Left)
    170148            | System.Windows.Forms.AnchorStyles.Right)));
    171       this.splitContainer2.Location = new System.Drawing.Point(12, 12);
     149      this.splitContainer2.Location = new System.Drawing.Point(6, 6);
    172150      this.splitContainer2.Name = "splitContainer2";
    173151      //
    174152      // splitContainer2.Panel1
    175153      //
    176       this.splitContainer2.Panel1.Controls.Add(this.splitContainer1);
     154      this.splitContainer2.Panel1.Controls.Add(this.groupBox2);
    177155      //
    178156      // splitContainer2.Panel2
    179157      //
    180158      this.splitContainer2.Panel2.Controls.Add(this.groupBoxDetails);
    181       this.splitContainer2.Panel2.Controls.Add(this.exportButton);
    182       this.splitContainer2.Size = new System.Drawing.Size(809, 605);
    183       this.splitContainer2.SplitterDistance = 377;
     159      this.splitContainer2.Size = new System.Drawing.Size(789, 522);
     160      this.splitContainer2.SplitterDistance = 367;
    184161      this.splitContainer2.TabIndex = 9;
     162      //
     163      // tabControl1
     164      //
     165      this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
     166            | System.Windows.Forms.AnchorStyles.Left)
     167            | System.Windows.Forms.AnchorStyles.Right)));
     168      this.tabControl1.Controls.Add(this.tabPage1);
     169      this.tabControl1.Controls.Add(this.tabPage2);
     170      this.tabControl1.Location = new System.Drawing.Point(12, 12);
     171      this.tabControl1.Name = "tabControl1";
     172      this.tabControl1.SelectedIndex = 0;
     173      this.tabControl1.Size = new System.Drawing.Size(809, 560);
     174      this.tabControl1.TabIndex = 10;
     175      //
     176      // tabPage1
     177      //
     178      this.tabPage1.Controls.Add(this.splitContainer2);
     179      this.tabPage1.Location = new System.Drawing.Point(4, 22);
     180      this.tabPage1.Name = "tabPage1";
     181      this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
     182      this.tabPage1.Size = new System.Drawing.Size(801, 534);
     183      this.tabPage1.TabIndex = 0;
     184      this.tabPage1.Text = "Parameters";
     185      this.tabPage1.UseVisualStyleBackColor = true;
     186      //
     187      // tabPage2
     188      //
     189      this.tabPage2.Controls.Add(this.groupBox3);
     190      this.tabPage2.Location = new System.Drawing.Point(4, 22);
     191      this.tabPage2.Name = "tabPage2";
     192      this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
     193      this.tabPage2.Size = new System.Drawing.Size(801, 534);
     194      this.tabPage2.TabIndex = 1;
     195      this.tabPage2.Text = "Results";
     196      this.tabPage2.UseVisualStyleBackColor = true;
     197      //
     198      // jsonItemBindingSource
     199      //
     200      this.jsonItemBindingSource.DataSource = typeof(HeuristicLab.JsonInterface.IJsonItem);
    185201      //
    186202      // ExportJsonDialog
     
    188204      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    189205      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    190       this.ClientSize = new System.Drawing.Size(833, 629);
    191       this.Controls.Add(this.splitContainer2);
     206      this.ClientSize = new System.Drawing.Size(833, 619);
     207      this.Controls.Add(this.exportButton);
     208      this.Controls.Add(this.tabControl1);
    192209      this.Name = "ExportJsonDialog";
    193210      this.RightToLeft = System.Windows.Forms.RightToLeft.No;
     
    195212      this.Text = "Export Json";
    196213      this.groupBoxDetails.ResumeLayout(false);
    197       ((System.ComponentModel.ISupportInitialize)(this.jsonItemBindingSource)).EndInit();
    198214      this.groupBox2.ResumeLayout(false);
    199215      this.groupBox3.ResumeLayout(false);
    200       this.splitContainer1.Panel1.ResumeLayout(false);
    201       this.splitContainer1.Panel2.ResumeLayout(false);
    202       ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
    203       this.splitContainer1.ResumeLayout(false);
    204216      this.splitContainer2.Panel1.ResumeLayout(false);
    205217      this.splitContainer2.Panel2.ResumeLayout(false);
    206218      ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit();
    207219      this.splitContainer2.ResumeLayout(false);
     220      this.tabControl1.ResumeLayout(false);
     221      this.tabPage1.ResumeLayout(false);
     222      this.tabPage2.ResumeLayout(false);
     223      ((System.ComponentModel.ISupportInitialize)(this.jsonItemBindingSource)).EndInit();
    208224      this.ResumeLayout(false);
    209225
     
    222238    private System.Windows.Forms.GroupBox groupBox2;
    223239    private System.Windows.Forms.GroupBox groupBox3;
    224     private System.Windows.Forms.SplitContainer splitContainer1;
    225240    private System.Windows.Forms.SplitContainer splitContainer2;
     241    private System.Windows.Forms.TabControl tabControl1;
     242    private System.Windows.Forms.TabPage tabPage1;
     243    private System.Windows.Forms.TabPage tabPage2;
    226244  }
    227245}
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface.OptimizerIntegration/Views/ExportJsonDialog.cs

    r17436 r17439  
    1818    private static SaveFileDialog SaveFileDialog { get; set; }
    1919    private IDictionary<int, UserControl> Hash2Control { get; set; } = new Dictionary<int, UserControl>();
     20    private IDictionary<TreeNode, JsonItemVMBase> Node2VM { get; set; } = new Dictionary<TreeNode, JsonItemVMBase>();
    2021    private IJsonItem Root { get; set; }
    2122    private IOptimizer Optimizer { get; set; }
     
    3839        Root = JsonItemConverter.Extract(Optimizer);
    3940        TreeNode parent = new TreeNode(Root.Name);
    40 
     41        treeView.AfterCheck += TreeView_AfterCheck;
    4142        BuildTreeNode(parent, Root);
    4243        treeView.Nodes.Add(parent);
     
    4445       
    4546      }
     47    }
     48
     49    private void TreeView_AfterCheck(object sender, TreeViewEventArgs e) {
     50      if (e.Action != TreeViewAction.Unknown) {
     51        if (Node2VM.TryGetValue(e.Node, out JsonItemVMBase vm)) {
     52          vm.Selected = e.Node.Checked;
     53        }
     54      }
    4655    }
    4756
     
    107116        vm.TreeNode = node;
    108117        vm.TreeView = treeView;
     118        Node2VM.Add(node, vm);
     119        node.Checked = vm.Selected;
    109120        UserControl control = vm.GetControl();
    110121        Hash2Control.Add(node.GetHashCode(), control);
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/Constants.cs

    r17435 r17439  
    1515    internal const string HLFileLocation = "HLFileLocation";
    1616    internal const string Parameters = "Parameters";
    17     internal const string ActivatedResults = "ActivatedResults";
     17    internal const string Results = "Results";
    1818
    1919    internal const string Template = @"{
     
    2323      },
    2424      '" + Parameters + @"': [],
    25       '" + ActivatedResults + @"': []
     25      '" + Results + @"': []
    2626    }";
    2727  }
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/Converters/MultiCheckedOperatorConverter.cs

    r17433 r17439  
    1616
    1717      dynamic val = item as dynamic;
    18       foreach (var op in val.Operators)
    19         val.Operators.SetItemCheckedState(op, GetOperatorState(op.Name, data));
     18      foreach (var op in val.Operators) {
     19        IJsonItem childItem = GetChildItem(op.Name, data);
     20        if(childItem != null) {
     21          if(childItem.Value is bool b) {
     22            val.Operators.SetItemCheckedState(op, b);
     23          }
     24          root.Inject((IItem)op, childItem, root);
     25        }
     26      }
    2027    }
    2128
     
    2431      dynamic val = value as dynamic;
    2532      foreach (var op in val.Operators) {
    26         item.AddChildren(new BoolJsonItem() {
     33        IJsonItem operatorItem = new BoolJsonItem() {
    2734          Name = op.Name,
    2835          Description = op.Description,
    2936          Value = val.Operators.ItemChecked(op),
    3037          Range = new bool[] { false, true }
    31         });
     38        };
     39        IJsonItem c = root.Extract((IItem)op, root);
     40        if(c != null && c.Children != null)
     41          operatorItem.AddChildren(c.Children);
     42        item.AddChildren(operatorItem);
    3243      }
    3344      return item;
     
    4253      return false;
    4354    }
     55
     56    private IJsonItem GetChildItem(string name, IJsonItem parent) {
     57      foreach(var c in parent.Children) {
     58        if (c.Name == name) return c;
     59      }
     60      return null;
     61    }
    4462    #endregion
    4563  }
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/Converters/ValueParameterConverter.cs

    r17433 r17439  
    1616      if (parameter.ActualValue == null && data.Value != null)
    1717        parameter.ActualValue = Instantiate(parameter.DataType);
    18       root.Inject(parameter.ActualValue, data, root);
     18
     19      if(parameter.ActualValue != null) {
     20          if (data.Children == null || data.Children.Count == 0)
     21            root.Inject(parameter.ActualValue, data, root);
     22          else
     23            root.Inject(parameter.ActualValue, data.Children?.First(), root);
     24         
     25      }
    1926    }
    2027
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/HeuristicLab.JsonInterface.csproj

    r17410 r17439  
    6464    <Compile Include="Converters\AlgorithmConverter.cs" />
    6565    <Compile Include="Converters\RegressionProblemDataConverter.cs" />
     66    <Compile Include="Converters\ResultParameterConverter.cs" />
    6667    <Compile Include="Converters\ValueLookupParameterConverter.cs" />
    6768    <Compile Include="Converters\ValueRangeConverter.cs" />
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/JCGenerator.cs

    r17435 r17439  
    2929      JArray resultItems = new JArray();
    3030      IList<IJsonItem> jsonItems = new List<IJsonItem>();
    31       string fullPath = Path.GetDirectoryName(Path.GetFullPath(path));
     31      string fullPath = Path.GetFullPath(path);
    3232     
    3333      // recursively filter items with values/ranges/actualNames
     
    5151      template[Constants.Metadata][Constants.HLFileLocation] = hlFilePath;
    5252      template[Constants.Parameters] = parameterItems;
    53       template[Constants.ActivatedResults] = resultItems;
     53      template[Constants.Results] = resultItems;
    5454
    5555      // serialize template and write file
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/JsonItemConverter.cs

    r17410 r17439  
    2020      = new Dictionary<Type, IJsonItemConverter>();
    2121
    22     private IDictionary<int, IJsonItem> Cache { get; set; }
     22    private IDictionary<int, IJsonItem> InjectCache { get; set; }
     23      = new Dictionary<int, IJsonItem>();
     24
     25    private IDictionary<int, IJsonItem> ExtractCache { get; set; }
    2326      = new Dictionary<int, IJsonItem>();
    2427
     
    5255   
    5356    public void Inject(IItem item, IJsonItem data, IJsonItemConverter root) {
    54       if(item != null && !Cache.ContainsKey(item.GetHashCode())) {
     57      if (item != null && !InjectCache.ContainsKey(item.GetHashCode())) {
    5558        IJsonItemConverter converter = GetConverter(item.GetType());
    5659        if(converter != null) converter.Inject(item, data, root);
     60        InjectCache.Add(item.GetHashCode(), data);
    5761      }
    5862    }
     
    6064    public IJsonItem Extract(IItem item, IJsonItemConverter root) {
    6165      int hash = item.GetHashCode();
    62       if (Cache.TryGetValue(hash, out IJsonItem val))
     66      if (ExtractCache.TryGetValue(hash, out IJsonItem val))
    6367        return val;
    6468      else {
     
    6670        if (converter == null) return new UnsupportedJsonItem();
    6771        IJsonItem tmp = GetConverter(item.GetType()).Extract(item, root);
    68         Cache.Add(hash, tmp);
     72        ExtractCache.Add(hash, tmp);
    6973        return tmp;
    7074      }
  • branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/JsonTemplateInstantiator.cs

    r17435 r17439  
    5858
    5959      // get algorthm data and object
    60       IJsonItem optimizerData = instData.Objects[optimizerName];
    61 
     60      IJsonItem optimizerData = instData.Objects.First().Value;
     61     
    6262      // inject configuration
    6363      JsonItemConverter.Inject(optimizer, optimizerData);
  • branches/3026_IntegrationIntoSymSpace/Heuristiclab.ConfigStarter/Program.cs

    r17436 r17439  
    4646
    4747      JCGenerator generator = new JCGenerator();
    48       generator.GenerateTemplate(@"C:\Workspace\Template.json", alg);
    49       JsonTemplateInstantiator.Instantiate(@"C:\Workspace\Template.json");
    50       /*
     48      generator.GenerateTemplate(@"C:\Workspace", "Template", alg);
     49      //JsonTemplateInstantiator.Instantiate(@"C:\Workspace\Template.json");
     50     
    5151      List<ICommandLineArgument> arguments = new List<ICommandLineArgument>();
    5252      arguments.Add(new StartArgument("JsonInterface"));
     
    5555
    5656      app.Run(arguments.ToArray());
    57       */
     57     
    5858    }
    5959  }
Note: See TracChangeset for help on using the changeset viewer.