diff --git a/Essay_Analysis_Tool/DiffViewerForm.Designer.cs b/Essay_Analysis_Tool/DiffViewerForm.Designer.cs
new file mode 100644
index 0000000..3af60df
--- /dev/null
+++ b/Essay_Analysis_Tool/DiffViewerForm.Designer.cs
@@ -0,0 +1,303 @@
+namespace Essay_Analysis_Tool
+{
+ partial class DiffViewerForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DiffViewerForm));
+ this.label6 = new System.Windows.Forms.Label();
+ this.label7 = new System.Windows.Forms.Label();
+ this.label5 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.label3 = new System.Windows.Forms.Label();
+ this.tbSecondFile = new System.Windows.Forms.TextBox();
+ this.btSecond = new System.Windows.Forms.Button();
+ this.label2 = new System.Windows.Forms.Label();
+ this.tbFirstFile = new System.Windows.Forms.TextBox();
+ this.btFirst = new System.Windows.Forms.Button();
+ this.ofdFile = new System.Windows.Forms.OpenFileDialog();
+ this.btCompare = new System.Windows.Forms.Button();
+ this.fctb1 = new FastColoredTextBoxNS.FastColoredTextBox();
+ this.fctb2 = new FastColoredTextBoxNS.FastColoredTextBox();
+ this.splitContainer1 = new System.Windows.Forms.SplitContainer();
+ ((System.ComponentModel.ISupportInitialize)(this.fctb1)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.fctb2)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
+ this.splitContainer1.Panel1.SuspendLayout();
+ this.splitContainer1.Panel2.SuspendLayout();
+ this.splitContainer1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // label6
+ //
+ this.label6.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.label6.AutoSize = true;
+ this.label6.Location = new System.Drawing.Point(136, 415);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(68, 13);
+ this.label6.TabIndex = 24;
+ this.label6.Text = "Deleted lines";
+ //
+ // label7
+ //
+ this.label7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.label7.BackColor = System.Drawing.Color.Pink;
+ this.label7.Location = new System.Drawing.Point(118, 415);
+ this.label7.Name = "label7";
+ this.label7.Size = new System.Drawing.Size(12, 13);
+ this.label7.TabIndex = 23;
+ this.label7.Text = " ";
+ //
+ // label5
+ //
+ this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.label5.AutoSize = true;
+ this.label5.Location = new System.Drawing.Point(30, 415);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(69, 13);
+ this.label5.TabIndex = 22;
+ this.label5.Text = "Inserted lines";
+ //
+ // label4
+ //
+ this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.label4.BackColor = System.Drawing.Color.PaleGreen;
+ this.label4.Location = new System.Drawing.Point(12, 415);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(12, 13);
+ this.label4.TabIndex = 21;
+ this.label4.Text = " ";
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(13, 40);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(60, 13);
+ this.label3.TabIndex = 20;
+ this.label3.Text = "Second file";
+ //
+ // tbSecondFile
+ //
+ this.tbSecondFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbSecondFile.Location = new System.Drawing.Point(79, 37);
+ this.tbSecondFile.Name = "tbSecondFile";
+ this.tbSecondFile.Size = new System.Drawing.Size(497, 20);
+ this.tbSecondFile.TabIndex = 19;
+ //
+ // btSecond
+ //
+ this.btSecond.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btSecond.Location = new System.Drawing.Point(582, 34);
+ this.btSecond.Name = "btSecond";
+ this.btSecond.Size = new System.Drawing.Size(30, 23);
+ this.btSecond.TabIndex = 18;
+ this.btSecond.Text = "...";
+ this.btSecond.UseVisualStyleBackColor = true;
+ this.btSecond.Click += new System.EventHandler(this.SelectSecondFileButton_Click);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(31, 13);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(42, 13);
+ this.label2.TabIndex = 17;
+ this.label2.Text = "First file";
+ //
+ // tbFirstFile
+ //
+ this.tbFirstFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbFirstFile.Location = new System.Drawing.Point(79, 11);
+ this.tbFirstFile.Name = "tbFirstFile";
+ this.tbFirstFile.Size = new System.Drawing.Size(497, 20);
+ this.tbFirstFile.TabIndex = 16;
+ //
+ // btFirst
+ //
+ this.btFirst.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btFirst.Location = new System.Drawing.Point(582, 8);
+ this.btFirst.Name = "btFirst";
+ this.btFirst.Size = new System.Drawing.Size(30, 23);
+ this.btFirst.TabIndex = 15;
+ this.btFirst.Text = "...";
+ this.btFirst.UseVisualStyleBackColor = true;
+ this.btFirst.Click += new System.EventHandler(this.SelectFirstFileButton_Click);
+ //
+ // btCompare
+ //
+ this.btCompare.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btCompare.Location = new System.Drawing.Point(537, 63);
+ this.btCompare.Name = "btCompare";
+ this.btCompare.Size = new System.Drawing.Size(75, 23);
+ this.btCompare.TabIndex = 25;
+ this.btCompare.Text = "Compare";
+ this.btCompare.UseVisualStyleBackColor = true;
+ this.btCompare.Click += new System.EventHandler(this.CompareButton_Click);
+ //
+ // fctb1
+ //
+ this.fctb1.AutoCompleteBracketsList = new char[] {
+ '(',
+ ')',
+ '{',
+ '}',
+ '[',
+ ']',
+ '\"',
+ '\"',
+ '\'',
+ '\''};
+ this.fctb1.AutoIndentCharsPatterns = "^\\s*[\\w\\.]+(\\s\\w+)?\\s*(?=)\\s*(?[^;=]+);\n^\\s*(case|default)\\s*[^:]*(" +
+ "?:)\\s*(?[^;]+);";
+ this.fctb1.AutoScrollMinSize = new System.Drawing.Size(27, 14);
+ this.fctb1.BackBrush = null;
+ this.fctb1.CharHeight = 14;
+ this.fctb1.CharWidth = 8;
+ this.fctb1.Cursor = System.Windows.Forms.Cursors.IBeam;
+ this.fctb1.DisabledColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(180)))), ((int)(((byte)(180)))), ((int)(((byte)(180)))));
+ this.fctb1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.fctb1.IsReplaceMode = false;
+ this.fctb1.Location = new System.Drawing.Point(0, 0);
+ this.fctb1.Name = "fctb1";
+ this.fctb1.Paddings = new System.Windows.Forms.Padding(0);
+ this.fctb1.ReadOnly = true;
+ this.fctb1.SelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255)))));
+ this.fctb1.ServiceColors = ((FastColoredTextBoxNS.ServiceColors)(resources.GetObject("fctb1.ServiceColors")));
+ this.fctb1.Size = new System.Drawing.Size(342, 311);
+ this.fctb1.TabIndex = 26;
+ this.fctb1.Zoom = 100;
+ this.fctb1.SelectionChanged += new System.EventHandler(this.FastColoredTextBox_VisibleRangeChanged);
+ this.fctb1.VisibleRangeChanged += new System.EventHandler(this.FastColoredTextBox_VisibleRangeChanged);
+ //
+ // fctb2
+ //
+ this.fctb2.AutoCompleteBracketsList = new char[] {
+ '(',
+ ')',
+ '{',
+ '}',
+ '[',
+ ']',
+ '\"',
+ '\"',
+ '\'',
+ '\''};
+ this.fctb2.AutoIndentCharsPatterns = "^\\s*[\\w\\.]+(\\s\\w+)?\\s*(?=)\\s*(?[^;=]+);\n^\\s*(case|default)\\s*[^:]*(" +
+ "?:)\\s*(?[^;]+);";
+ this.fctb2.AutoScrollMinSize = new System.Drawing.Size(27, 14);
+ this.fctb2.BackBrush = null;
+ this.fctb2.CharHeight = 14;
+ this.fctb2.CharWidth = 8;
+ this.fctb2.Cursor = System.Windows.Forms.Cursors.IBeam;
+ this.fctb2.DisabledColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(180)))), ((int)(((byte)(180)))), ((int)(((byte)(180)))));
+ this.fctb2.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.fctb2.IsReplaceMode = false;
+ this.fctb2.Location = new System.Drawing.Point(0, 0);
+ this.fctb2.Name = "fctb2";
+ this.fctb2.Paddings = new System.Windows.Forms.Padding(0);
+ this.fctb2.ReadOnly = true;
+ this.fctb2.SelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255)))));
+ this.fctb2.ServiceColors = ((FastColoredTextBoxNS.ServiceColors)(resources.GetObject("fctb2.ServiceColors")));
+ this.fctb2.Size = new System.Drawing.Size(352, 311);
+ this.fctb2.TabIndex = 27;
+ this.fctb2.Zoom = 100;
+ this.fctb2.SelectionChanged += new System.EventHandler(this.FastColoredTextBox_VisibleRangeChanged);
+ this.fctb2.VisibleRangeChanged += new System.EventHandler(this.FastColoredTextBox_VisibleRangeChanged);
+ //
+ // splitContainer1
+ //
+ this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.splitContainer1.Location = new System.Drawing.Point(12, 92);
+ this.splitContainer1.Name = "splitContainer1";
+ //
+ // splitContainer1.Panel1
+ //
+ this.splitContainer1.Panel1.Controls.Add(this.fctb1);
+ //
+ // splitContainer1.Panel2
+ //
+ this.splitContainer1.Panel2.Controls.Add(this.fctb2);
+ this.splitContainer1.Size = new System.Drawing.Size(698, 311);
+ this.splitContainer1.SplitterDistance = 342;
+ this.splitContainer1.TabIndex = 28;
+ //
+ // DiffViewerForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(722, 437);
+ this.Controls.Add(this.splitContainer1);
+ this.Controls.Add(this.btCompare);
+ this.Controls.Add(this.label6);
+ this.Controls.Add(this.label7);
+ this.Controls.Add(this.label5);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.tbSecondFile);
+ this.Controls.Add(this.btSecond);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.tbFirstFile);
+ this.Controls.Add(this.btFirst);
+ this.Name = "DiffViewerForm";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "Diff Viewer";
+ ((System.ComponentModel.ISupportInitialize)(this.fctb1)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.fctb2)).EndInit();
+ this.splitContainer1.Panel1.ResumeLayout(false);
+ this.splitContainer1.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
+ this.splitContainer1.ResumeLayout(false);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.Label label7;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.TextBox tbSecondFile;
+ private System.Windows.Forms.Button btSecond;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.TextBox tbFirstFile;
+ private System.Windows.Forms.Button btFirst;
+ private System.Windows.Forms.OpenFileDialog ofdFile;
+ private System.Windows.Forms.Button btCompare;
+ private FastColoredTextBoxNS.FastColoredTextBox fctb1;
+ private FastColoredTextBoxNS.FastColoredTextBox fctb2;
+ private System.Windows.Forms.SplitContainer splitContainer1;
+ }
+}
\ No newline at end of file
diff --git a/Essay_Analysis_Tool/DiffViewerForm.cs b/Essay_Analysis_Tool/DiffViewerForm.cs
new file mode 100644
index 0000000..379b091
--- /dev/null
+++ b/Essay_Analysis_Tool/DiffViewerForm.cs
@@ -0,0 +1,585 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Text;
+using System.Windows.Forms;
+using Essay_Analysis_Tool.DiffMergeStuffs;
+using FastColoredTextBoxNS;
+
+namespace Essay_Analysis_Tool
+{
+ public partial class DiffViewerForm : Form
+ {
+ private int _updating;
+ private static readonly Style _greenStyle;
+ private static readonly Style _redStyle;
+
+ static DiffViewerForm()
+ {
+ _greenStyle = new MarkerStyle(new SolidBrush(Color.FromArgb(50, Color.Lime)));
+ _redStyle = new MarkerStyle(new SolidBrush(Color.FromArgb(50, Color.Red)));
+ }
+
+ public DiffViewerForm()
+ : this("") { }
+
+ ///
+ /// Initialize a new form.
+ ///
+ /// Absolute or relative file path.
+ public DiffViewerForm(string file)
+ : this(file, "") { }
+
+ ///
+ /// Initialize a new form.
+ ///
+ /// Absolute or relative file path.
+ /// Absolute or relative file path.
+ public DiffViewerForm(string file1, string file2)
+ {
+ InitializeComponent();
+
+ tbFirstFile.Text = file1;
+ tbSecondFile.Text = file2;
+ }
+
+ private void SelectFirstFileButton_Click(object sender, EventArgs e)
+ {
+ if (ofdFile.ShowDialog() == DialogResult.OK)
+ tbFirstFile.Text = ofdFile.FileName;
+ }
+
+ private void SelectSecondFileButton_Click(object sender, EventArgs e)
+ {
+ if (ofdFile.ShowDialog() == DialogResult.OK)
+ tbSecondFile.Text = ofdFile.FileName;
+ }
+
+ private void CompareButton_Click(object sender, EventArgs e)
+ {
+ if (!File.Exists(tbFirstFile.Text) || !File.Exists(tbSecondFile.Text))
+ {
+ MessageBox.Show(this, "Please select a valid file", "Invalid file");
+ return;
+ }
+
+ fctb1.Clear();
+ fctb2.Clear();
+
+ Cursor = Cursors.WaitCursor;
+
+ if (Path.GetExtension(tbFirstFile.Text).ToLower() == ".cs")
+ fctb1.Language = fctb2.Language = Language.CSharp;
+ else
+ fctb1.Language = fctb2.Language = Language.Custom;
+
+ var source1 = Lines.Load(tbFirstFile.Text);
+ var source2 = Lines.Load(tbSecondFile.Text);
+
+ source1.Merge(source2);
+
+ BeginUpdate();
+
+ Process(source1);
+
+ EndUpdate();
+
+ Cursor = Cursors.Default;
+ }
+
+ private void FastColoredTextBox_VisibleRangeChanged(object sender, EventArgs e)
+ {
+ if (_updating > 0)
+ return;
+
+ var vPos = (sender as FastColoredTextBox).VerticalScroll.Value;
+ var curLine = (sender as FastColoredTextBox).Selection.Start.iLine;
+
+ if (sender == fctb2)
+ UpdateScroll(fctb1, vPos, curLine);
+ else
+ UpdateScroll(fctb2, vPos, curLine);
+
+ fctb1.Refresh();
+ fctb2.Refresh();
+ }
+
+ private void UpdateScroll(FastColoredTextBox tb, int vPos, int curLine)
+ {
+ if (_updating > 0)
+ return;
+ //
+ BeginUpdate();
+ //
+ if (vPos <= tb.VerticalScroll.Maximum)
+ {
+ tb.VerticalScroll.Value = vPos;
+ tb.UpdateScrollbars();
+ }
+
+ if (curLine < tb.LinesCount)
+ tb.Selection = new Range(tb, 0, curLine, 0, curLine);
+ //
+ EndUpdate();
+ }
+
+ private void EndUpdate()
+ {
+ _updating--;
+ }
+
+ private void BeginUpdate()
+ {
+ _updating++;
+ }
+
+ private void Process(Lines lines)
+ {
+ foreach (var line in lines)
+ {
+ switch (line.state)
+ {
+ case DiffType.None:
+ fctb1.AppendText(line.line + Environment.NewLine);
+ fctb2.AppendText(line.line + Environment.NewLine);
+ break;
+ case DiffType.Inserted:
+ fctb1.AppendText(Environment.NewLine);
+ fctb2.AppendText(line.line + Environment.NewLine, _greenStyle);
+ break;
+ case DiffType.Deleted:
+ fctb1.AppendText(line.line + Environment.NewLine, _redStyle);
+ fctb2.AppendText(Environment.NewLine);
+ break;
+ }
+ if (line.subLines != null)
+ Process(line.subLines);
+ }
+ }
+ }
+
+ #region Merge stuffs
+
+ namespace DiffMergeStuffs
+ {
+ public class SimpleDiff
+ {
+ private IList _left;
+ private IList _right;
+ private int[,] _matrix;
+ private bool _matrixCreated;
+ private int _preSkip;
+ private int _postSkip;
+
+ private Func _compareFunc;
+
+ public SimpleDiff(IList left, IList right)
+ {
+ _left = left;
+ _right = right;
+
+ InitializeCompareFunc();
+ }
+
+ public event EventHandler> LineUpdate;
+
+ public TimeSpan ElapsedTime { get; private set; }
+
+ ///
+ /// This is the sole public method and it initializes
+ /// the LCS matrix the first time it's called, and
+ /// proceeds to fire a series of LineUpdate events
+ ///
+ public void RunDiff()
+ {
+ if (!_matrixCreated)
+ {
+ Stopwatch sw = new Stopwatch();
+ sw.Start();
+ CalculatePreSkip();
+ CalculatePostSkip();
+ CreateLCSMatrix();
+ sw.Stop();
+ this.ElapsedTime = sw.Elapsed;
+ }
+
+ for (int i = 0; i < _preSkip; i++)
+ {
+ FireLineUpdate(DiffType.None, i, -1);
+ }
+
+ int totalSkip = _preSkip + _postSkip;
+ ShowDiff(_left.Count - totalSkip, _right.Count - totalSkip);
+
+ int leftLen = _left.Count;
+ for (int i = _postSkip; i > 0; i--)
+ {
+ FireLineUpdate(DiffType.None, leftLen - i, -1);
+ }
+ }
+
+ ///
+ /// This method is an optimization that
+ /// skips matching elements at the end of the
+ /// two arrays being diff'ed.
+ /// Care's taken so that this will never
+ /// overlap with the pre-skip.
+ ///
+ private void CalculatePostSkip()
+ {
+ int leftLen = _left.Count;
+ int rightLen = _right.Count;
+ while (_postSkip < leftLen && _postSkip < rightLen &&
+ _postSkip < (leftLen - _preSkip) &&
+ _compareFunc(_left[leftLen - _postSkip - 1], _right[rightLen - _postSkip - 1]))
+ {
+ _postSkip++;
+ }
+ }
+
+ ///
+ /// This method is an optimization that
+ /// skips matching elements at the start of
+ /// the arrays being diff'ed
+ ///
+ private void CalculatePreSkip()
+ {
+ int leftLen = _left.Count;
+ int rightLen = _right.Count;
+ while (_preSkip < leftLen && _preSkip < rightLen &&
+ _compareFunc(_left[_preSkip], _right[_preSkip]))
+ {
+ _preSkip++;
+ }
+ }
+
+ ///
+ /// This traverses the elements using the LCS matrix
+ /// and fires appropriate events for added, subtracted,
+ /// and unchanged lines.
+ /// It's recursively called till we run out of items.
+ ///
+ ///
+ ///
+ private void ShowDiff(int leftIndex, int rightIndex)
+ {
+ if (leftIndex > 0 && rightIndex > 0 &&
+ _compareFunc(_left[_preSkip + leftIndex - 1], _right[_preSkip + rightIndex - 1]))
+ {
+ ShowDiff(leftIndex - 1, rightIndex - 1);
+ FireLineUpdate(DiffType.None, _preSkip + leftIndex - 1, -1);
+ }
+ else
+ {
+ if (rightIndex > 0 &&
+ (leftIndex == 0 ||
+ _matrix[leftIndex, rightIndex - 1] >= _matrix[leftIndex - 1, rightIndex]))
+ {
+ ShowDiff(leftIndex, rightIndex - 1);
+ FireLineUpdate(DiffType.Inserted, -1, _preSkip + rightIndex - 1);
+ }
+ else if (leftIndex > 0 &&
+ (rightIndex == 0 ||
+ _matrix[leftIndex, rightIndex - 1] < _matrix[leftIndex - 1, rightIndex]))
+ {
+ ShowDiff(leftIndex - 1, rightIndex);
+ FireLineUpdate(DiffType.Deleted, _preSkip + leftIndex - 1, -1);
+ }
+ }
+
+ }
+
+ ///
+ /// This is the core method in the entire class,
+ /// and uses the standard LCS calculation algorithm.
+ ///
+ private void CreateLCSMatrix()
+ {
+ int totalSkip = _preSkip + _postSkip;
+ if (totalSkip >= _left.Count || totalSkip >= _right.Count)
+ return;
+
+ // We only create a matrix large enough for the
+ // unskipped contents of the diff'ed arrays
+ _matrix = new int[_left.Count - totalSkip + 1, _right.Count - totalSkip + 1];
+
+ for (int i = 1; i <= _left.Count - totalSkip; i++)
+ {
+ // Simple optimization to avoid this calculation
+ // inside the outer loop (may have got JIT optimized
+ // but my tests showed a minor improvement in speed)
+ int leftIndex = _preSkip + i - 1;
+
+ // Again, instead of calculating the adjusted index inside
+ // the loop, I initialize it under the assumption that
+ // incrementing will be a faster operation on most CPUs
+ // compared to addition. Again, this may have got JIT
+ // optimized but my tests showed a minor speed difference.
+ for (int j = 1, rightIndex = _preSkip + 1; j <= _right.Count - totalSkip; j++, rightIndex++)
+ {
+ _matrix[i, j] = _compareFunc(_left[leftIndex], _right[rightIndex - 1])
+ ? _matrix[i - 1, j - 1] + 1
+ : Math.Max(_matrix[i, j - 1], _matrix[i - 1, j]);
+ }
+ }
+
+ _matrixCreated = true;
+ }
+
+ private void FireLineUpdate(DiffType diffType, int leftIndex, int rightIndex)
+ {
+ var local = this.LineUpdate;
+
+ if (local == null)
+ return;
+
+ T lineValue = leftIndex >= 0 ? _left[leftIndex] : _right[rightIndex];
+
+ local(this, new DiffEventArgs(diffType, lineValue, leftIndex, rightIndex));
+ }
+
+ private void InitializeCompareFunc()
+ {
+ // Special case for String types
+ if (typeof(T) == typeof(String))
+ {
+ _compareFunc = StringCompare;
+ }
+ else
+ {
+ _compareFunc = DefaultCompare;
+ }
+ }
+
+ ///
+ /// This comparison is specifically
+ /// for strings, and was nearly thrice as
+ /// fast as the default comparison operation.
+ ///
+ ///
+ ///
+ ///
+ private bool StringCompare(T left, T right)
+ {
+ return Object.Equals(left, right);
+ }
+
+ private bool DefaultCompare(T left, T right)
+ {
+ return left.Equals(right);
+ }
+ }
+
+ [Flags]
+ public enum DiffType
+ {
+ None = 0,
+ Inserted = 1,
+ Deleted = 2
+ }
+
+ public class DiffEventArgs : EventArgs
+ {
+ public DiffType DiffType { get; set; }
+
+ public T LineValue { get; private set; }
+ public int LeftIndex { get; private set; }
+ public int RightIndex { get; private set; }
+
+ public DiffEventArgs(DiffType diffType, T lineValue, int leftIndex, int rightIndex)
+ {
+ this.DiffType = diffType;
+ this.LineValue = lineValue;
+ this.LeftIndex = leftIndex;
+ this.RightIndex = rightIndex;
+ }
+ }
+
+ ///
+ /// Line of file
+ ///
+ public class Line
+ {
+ ///
+ /// Source string
+ ///
+ public readonly string line;
+
+ ///
+ /// Inserted strings
+ ///
+ public Lines subLines;
+
+ ///
+ /// Line state
+ ///
+ public DiffType state;
+
+ public Line(string line)
+ {
+ this.line = line;
+ }
+
+ ///
+ /// Equals
+ ///
+ public override bool Equals(object obj)
+ {
+ return Object.Equals(line, ((Line)obj).line);
+ }
+
+ public static bool operator ==(Line line1, Line line2)
+ {
+ return Object.Equals(line1.line, line2.line);
+ }
+
+ public static bool operator !=(Line line1, Line line2)
+ {
+ return !Object.Equals(line1.line, line2.line);
+ }
+
+ public override string ToString()
+ {
+ return line;
+ }
+ }
+
+ ///
+ /// File as list of lines.
+ ///
+ public class Lines : List, IEquatable
+ {
+ private Line fictiveLine = new Line("===fictive line===") { state = DiffType.Deleted };
+
+ public Lines() { }
+
+ public Lines(int capacity)
+ : base(capacity) { }
+
+ public Line this[int i]
+ {
+ get
+ {
+ if (i == -1) return fictiveLine;
+ return base[i];
+ }
+
+ set
+ {
+ if (i == -1) fictiveLine = value;
+ base[i] = value;
+ }
+ }
+
+ ///
+ /// Load from file
+ ///
+ public static Lines Load(string fileName, Encoding enc = null)
+ {
+ Lines lines = new Lines();
+ foreach (var line in File.ReadAllLines(fileName, enc ?? Encoding.Default))
+ lines.Add(new Line(line));
+
+ return lines;
+ }
+
+ ///
+ /// Merge lines
+ ///
+ public void Merge(Lines lines)
+ {
+ SimpleDiff diff = new SimpleDiff(this, lines);
+ int iLine = -1;
+
+ diff.LineUpdate += (o, e) =>
+ {
+ if (e.DiffType == DiffType.Inserted)
+ {
+ if (this[iLine].subLines == null)
+ this[iLine].subLines = new Lines();
+ e.LineValue.state = DiffType.Inserted;
+ this[iLine].subLines.Add(e.LineValue);
+ }
+ else
+ {
+ iLine++;
+ this[iLine].state = e.DiffType;
+ if (iLine > 0 &&
+ this[iLine - 1].state == DiffType.Deleted &&
+ this[iLine - 1].subLines == null &&
+ e.DiffType == DiffType.None)
+ this[iLine - 1].subLines = new Lines();
+ }
+ };
+
+ diff.RunDiff();
+ }
+
+ ///
+ /// Clone
+ ///
+ public Lines Clone()
+ {
+ Lines result = new Lines(this.Count);
+ foreach (var line in this)
+ result.Add(new Line(line.line));
+
+ return result;
+ }
+
+ ///
+ /// Is lines equal?
+ ///
+ public bool Equals(Lines other)
+ {
+ if (Count != other.Count)
+ return false;
+ for (int i = 0; i < Count; i++)
+ if (this[i] != other[i])
+ return false;
+ return true;
+ }
+
+ ///
+ /// Transform tree to list
+ ///
+ public Lines Expand()
+ {
+ return Expand(-1, Count - 1);
+ }
+
+ ///
+ /// Transform tree to list
+ ///
+ public Lines Expand(int from, int to)
+ {
+ Lines result = new Lines();
+ for (int i = from; i <= to; i++)
+ {
+ if (this[i].state != DiffType.Deleted)
+ result.Add(this[i]);
+ if (this[i].subLines != null)
+ result.AddRange(this[i].subLines.Expand());
+ }
+
+ return result;
+ }
+ }
+
+ public class ConflictedLine : Line
+ {
+ public readonly Lines version1;
+ public readonly Lines version2;
+
+ public ConflictedLine(Lines version1, Lines version2)
+ : base("?")
+ {
+ this.version1 = version1;
+ this.version2 = version2;
+ }
+ }
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/Essay_Analysis_Tool/DiffViewerForm.resx b/Essay_Analysis_Tool/DiffViewerForm.resx
new file mode 100644
index 0000000..1089076
--- /dev/null
+++ b/Essay_Analysis_Tool/DiffViewerForm.resx
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+
+ AAEAAAD/////AQAAAAAAAAAMAgAAAFdGYXN0Q29sb3JlZFRleHRCb3gsIFZlcnNpb249Mi4xNi4yNi4w
+ LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWZiOGFhMTJiOTk0ZWY2MWIMAwAAAFFTeXN0
+ ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2Vu
+ PWIwM2Y1ZjdmMTFkNTBhM2EFAQAAACJGYXN0Q29sb3JlZFRleHRCb3hOUy5TZXJ2aWNlQ29sb3JzBgAA
+ ACg8Q29sbGFwc2VNYXJrZXJGb3JlQ29sb3I+a19fQmFja2luZ0ZpZWxkKDxDb2xsYXBzZU1hcmtlckJh
+ Y2tDb2xvcj5rX19CYWNraW5nRmllbGQqPENvbGxhcHNlTWFya2VyQm9yZGVyQ29sb3I+a19fQmFja2lu
+ Z0ZpZWxkJjxFeHBhbmRNYXJrZXJGb3JlQ29sb3I+a19fQmFja2luZ0ZpZWxkJjxFeHBhbmRNYXJrZXJC
+ YWNrQ29sb3I+a19fQmFja2luZ0ZpZWxkKDxFeHBhbmRNYXJrZXJCb3JkZXJDb2xvcj5rX19CYWNraW5n
+ RmllbGQEBAQEBAQUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5EcmF3aW5nLkNvbG9yAwAA
+ ABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAAUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5E
+ cmF3aW5nLkNvbG9yAwAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAACAAAABfz///8UU3lzdGVtLkRy
+ YXdpbmcuQ29sb3IEAAAABG5hbWUFdmFsdWUKa25vd25Db2xvcgVzdGF0ZQEAAAAJBwcDAAAACgAAAAAA
+ AAAAlgABAAH7/////P///woAAAAAAAAAAKQAAQAB+v////z///8KAAAAAAAAAACWAAEAAfn////8////
+ CgAAAAAAAAAAjQABAAH4/////P///woAAAAAAAAAAKQAAQAB9/////z///8KAAAAAAAAAACWAAEACw==
+
+
+
+
+ AAEAAAD/////AQAAAAAAAAAMAgAAAFdGYXN0Q29sb3JlZFRleHRCb3gsIFZlcnNpb249Mi4xNi4yNi4w
+ LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWZiOGFhMTJiOTk0ZWY2MWIMAwAAAFFTeXN0
+ ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2Vu
+ PWIwM2Y1ZjdmMTFkNTBhM2EFAQAAACJGYXN0Q29sb3JlZFRleHRCb3hOUy5TZXJ2aWNlQ29sb3JzBgAA
+ ACg8Q29sbGFwc2VNYXJrZXJGb3JlQ29sb3I+a19fQmFja2luZ0ZpZWxkKDxDb2xsYXBzZU1hcmtlckJh
+ Y2tDb2xvcj5rX19CYWNraW5nRmllbGQqPENvbGxhcHNlTWFya2VyQm9yZGVyQ29sb3I+a19fQmFja2lu
+ Z0ZpZWxkJjxFeHBhbmRNYXJrZXJGb3JlQ29sb3I+a19fQmFja2luZ0ZpZWxkJjxFeHBhbmRNYXJrZXJC
+ YWNrQ29sb3I+a19fQmFja2luZ0ZpZWxkKDxFeHBhbmRNYXJrZXJCb3JkZXJDb2xvcj5rX19CYWNraW5n
+ RmllbGQEBAQEBAQUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5EcmF3aW5nLkNvbG9yAwAA
+ ABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAAUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5E
+ cmF3aW5nLkNvbG9yAwAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAACAAAABfz///8UU3lzdGVtLkRy
+ YXdpbmcuQ29sb3IEAAAABG5hbWUFdmFsdWUKa25vd25Db2xvcgVzdGF0ZQEAAAAJBwcDAAAACgAAAAAA
+ AAAAlgABAAH7/////P///woAAAAAAAAAAKQAAQAB+v////z///8KAAAAAAAAAACWAAEAAfn////8////
+ CgAAAAAAAAAAjQABAAH4/////P///woAAAAAAAAAAKQAAQAB9/////z///8KAAAAAAAAAACWAAEACw==
+
+
+
\ No newline at end of file
diff --git a/Essay_Analysis_Tool/MainForm.Designer.cs b/Essay_Analysis_Tool/MainForm.Designer.cs
index 4512489..0a868a4 100644
--- a/Essay_Analysis_Tool/MainForm.Designer.cs
+++ b/Essay_Analysis_Tool/MainForm.Designer.cs
@@ -98,6 +98,7 @@ private void InitializeComponent()
this.tsFiles = new FarsiLibrary.Win.FATabStrip();
this.documentMap1 = new FastColoredTextBoxNS.DocumentMap();
this.documentMap = new FastColoredTextBoxNS.DocumentMap();
+ this.diffToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
this.tsMain.SuspendLayout();
@@ -255,7 +256,8 @@ private void InitializeComponent()
this.statusBarToolStripMenuItem,
this.syntaxHighlightingToolStripMenuItem,
this.documentMapToolStripMenuItem,
- this.loggerToolStripMenuItem});
+ this.loggerToolStripMenuItem,
+ this.diffToolStripMenuItem});
this.documentMapToolStripItem.Name = "documentMapToolStripItem";
this.documentMapToolStripItem.Size = new System.Drawing.Size(44, 20);
this.documentMapToolStripItem.Text = "View";
@@ -264,7 +266,7 @@ private void InitializeComponent()
//
this.statusBarToolStripMenuItem.CheckOnClick = true;
this.statusBarToolStripMenuItem.Name = "statusBarToolStripMenuItem";
- this.statusBarToolStripMenuItem.Size = new System.Drawing.Size(178, 22);
+ this.statusBarToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.statusBarToolStripMenuItem.Text = "Status Bar";
this.statusBarToolStripMenuItem.Click += new System.EventHandler(this.StatusBarToolStripMenuItem_Click);
//
@@ -281,7 +283,7 @@ private void InitializeComponent()
this.visualBasicToolStripMenuItem,
this.xMLToolStripMenuItem});
this.syntaxHighlightingToolStripMenuItem.Name = "syntaxHighlightingToolStripMenuItem";
- this.syntaxHighlightingToolStripMenuItem.Size = new System.Drawing.Size(178, 22);
+ this.syntaxHighlightingToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.syntaxHighlightingToolStripMenuItem.Text = "Syntax Highlighting";
//
// noneToolStripMenuItem
@@ -350,14 +352,14 @@ private void InitializeComponent()
// documentMapToolStripMenuItem
//
this.documentMapToolStripMenuItem.Name = "documentMapToolStripMenuItem";
- this.documentMapToolStripMenuItem.Size = new System.Drawing.Size(178, 22);
+ this.documentMapToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.documentMapToolStripMenuItem.Text = "Document Map";
this.documentMapToolStripMenuItem.Click += new System.EventHandler(this.DocumentMapToolStripMenuItem_Click);
//
// loggerToolStripMenuItem
//
this.loggerToolStripMenuItem.Name = "loggerToolStripMenuItem";
- this.loggerToolStripMenuItem.Size = new System.Drawing.Size(178, 22);
+ this.loggerToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.loggerToolStripMenuItem.Text = "Logger";
this.loggerToolStripMenuItem.Click += new System.EventHandler(this.LoggerToolStripMenuItem_Click);
//
@@ -644,6 +646,13 @@ private void InitializeComponent()
this.documentMap.Text = "documentMap";
this.documentMap.Visible = false;
//
+ // diffToolStripMenuItem
+ //
+ this.diffToolStripMenuItem.Name = "diffToolStripMenuItem";
+ this.diffToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.diffToolStripMenuItem.Text = "Diff";
+ this.diffToolStripMenuItem.Click += new System.EventHandler(this.DiffToolStripMenuItem_Click);
+ //
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -731,6 +740,7 @@ private void InitializeComponent()
private System.Windows.Forms.ToolStripButton hlCurrentLineToolStripButton;
private System.Windows.Forms.ImageList imageList1;
private System.Windows.Forms.ToolStripMenuItem loggerToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem diffToolStripMenuItem;
}
}
diff --git a/Essay_Analysis_Tool/MainForm.cs b/Essay_Analysis_Tool/MainForm.cs
index 2d78935..bb9a44b 100644
--- a/Essay_Analysis_Tool/MainForm.cs
+++ b/Essay_Analysis_Tool/MainForm.cs
@@ -970,6 +970,31 @@ private void SanitizeTabStrip()
}
}
+ private bool IsSavedTab(string tagName) => tagName != null;
+
+ private void DiffToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ List filePaths = new List();
+
+ foreach (FATabStripItem item in tsFiles.Items)
+ {
+ string filePath = (string)item.Tag;
+
+ if (IsSavedTab(filePath))
+ filePaths.Add(filePath);
+
+ if (filePaths.Count == 2)
+ break;
+ }
+
+ if (filePaths.Count == 1)
+ new DiffViewerForm(filePaths[0]).Show();
+ else if (filePaths.Count == 2)
+ new DiffViewerForm(filePaths[0], filePaths[1]).Show();
+ else
+ new DiffViewerForm().Show();
+ }
+
#endregion
#region Document Map Functionality
diff --git a/Essay_Analysis_Tool/MainForm.resx b/Essay_Analysis_Tool/MainForm.resx
index dd40328..2cb6045 100644
--- a/Essay_Analysis_Tool/MainForm.resx
+++ b/Essay_Analysis_Tool/MainForm.resx
@@ -133,48 +133,48 @@
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
- YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAOjSURBVEhLpZVLSFRRGMdvT3tRtGhxMTNqUbSIQui1qaAW
- kVGzqUCIRKRNgSWSiNIgDu4kaCW0aRW48DGZaWJS+ULUmUrJUhlndGac171zH/PMuV/nO3PPzDhOpnXg
- z5m54u/3ne8bzuX+d4GT2wVi3mGQtx/XQlw+ALdF/9Pq1dnZWdTb22vq7++n6evrM+H37u5uU1dXl8ls
- Npva29tNra2tppaWFtOn/qqX1tE7bT+/Xeudnbry4bv1Ws/PL2efQjDviI5Mr+bm5n1jY2NzbrcbFhcX
- weVygdPpXBF8jllYWACP+y2I3kZQA2UQEa9DVLxKdgPYbbdlwXHg4SpJU1MTb7Va7fjPNpsNHA4H2O12
- uuMzDBO4XV8J/AWExfuwLJ+BROgOJMJlZL9FCjkXD7r5V5q88+aKdjEBAubn5ymQwRmYncTn6QElUAtx
- 6QoB3wMt+gK02GuyN8Lc1MnlqL/go6bsfYQz0fFpAQKwcgQyOD7DlmGwhQGvGUJiJan+PCQilaDF3wNo
- QSqZnbqciPsLLKDur9ak7cd0fFqAEKw8cwYMvLS0RCP4ekAVquGXfImc4AEBv6ISPMns5MVEVDg4rCn7
- HmvCjkIdz3ENDQ1UgCCsHHcGZnCPx0MT8FlAEZogJt2FhHqZSvAk2K6ZyRPLqje/RVN239U0bqeOTwos
- FgvpTnKwCMwGe71e8Pl8NJJA2hR8RiXLCpEoF8iJrkLAZQh5bLwR1G2ndHRy1dTU8BMTE/bp6Wl6AtaO
- bLDf74dAIACC4AJZfEMkzyEcrIGIVEVihB8/aoXRzwU3dGx6MQECsTXZVTNwEi7QiKIIkjhJRH0k70CR
- PsL4kNlVXFx8SMemFwrGx8ftCMTW4I6ClVUnoZhgMJgzIyMjizkFFRUV/PDwMBVgaxDMqs+EM5AkSTSy
- LKc+Y9YtwKozq2dwBsUoipIKe0YYuQXl5eVUMDMzQ4fMBKz6TDgCVVVdESb6qwB/pjgDFGRXnwkPhUIQ
- Dodp8DPLmoLBwUE7Vo3DZYLUr0WvPhMeiURSYaI/CkpKSviBgQEqwDmw6jPbw6pn8Gg0msq6BOQlsyFB
- LBaDeDxOBfh9TYHBYNiwAMEoWdcJUEBekY7/ncHQ0JAzl2AHz/NFHR0d5JZwrbpNsy88DBaSK+TdvVRY
- WHiaMDcn0cmVR3KUzOEJuVXb6urqejBGo3FDqa+v7y4tLa0krAKSTQjOXltJtpHs+cfg/Z9ROcf9BsiU
- 2rESO8DGAAAAAElFTkSuQmCC
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAOjSURBVEhLpZVLSFRRGMdvT3tRtGhxKTNqUQRBEfTaZFCL
+ yKjZVCBEEtKmwJIoJGkQh3YSuBLatApcmE5m2jBJ5YtQZ0ojc4pxxnk4r3vnPuaZc7/Od+aemXGcTOvA
+ nzNzxd/vO983nMv97wIvtwnEsj0grz+gxbidANwa/U+LV3d391GLxWLq7++nsVqtJvze29tr6unpMZnN
+ ZlNnZ6epo6PD1N7ebvrQf/+Z/dPVl9MT5y0/vp59981+vm/68/EHEC3bqyPzq62tbdvo6OhPv98PHo8H
+ fD4feL3eBcHnmNnZWQj4X4MYfAJq5CYkxAuQFM+R3QAu5xVZcO+4vUjS0tLC2+12F/6z0+kEt9sNLpeL
+ 7vgMwwR+3xcCb4W4eAPm5WOQiV2FTPwm2S+TQk6ko37+uSZvvLSgXUyAgJmZGQpkcAZmJwkF+kCJPIK0
+ dJaAr4OWbAUt9YLsT+DH5KH5ZLj8vaZsvYMz0fF5AQKwcgQyOD7DlmGwhZGgGWJiPan+JGQS9aCl3wJo
+ USpxTFZm0uFyG6jbH2rS+v06Pi9ACFZeOAMGnpuboxFCfaAKD+GXXElOcIuAn1MJnsQxcTqTFHYNa8q2
+ u5qwoULHc1xzczMVIAgrx52BGTwQCNBEQjZQhBZISdcgo56hEjwJtmt68uC8GtzZrimbr2kat1HHZwU2
+ m410JztYBBaDg8EghEIhGkkgbYo+ppJ5hUiUU+RE5yDiM8QCTt4I6rrDOjq7Ghoa+PHxcdfU1BQ9AWtH
+ MTgcDkMkEgFB8IEsviKSpxCPNkBCuk9ihO/fHwmfPpZf1LH5xQQIxNYUV83AWbhAI4oiSOIkEVlJ3oAi
+ vYexIbOvqqpqt47NLxSMjY25EIitwR0FC6vOQjHRaLRkRkZGPCUFdXV1/PDwMBVgaxDMqi+EM5AkSTSy
+ LOc+Y5YtwKoLq2dwBsUoipILe0YYpQW1tbVU4HA46JCZgFVfCEegqqoLwkR/FeDPFGeAguLqC+GxWAzi
+ 8TgNfmZZUjA4OOjCqnG4TJD7tejVF8ITiUQuTPRHQXV1NT8wMEAFOAdWfWF7WPUMnkwmc1mWgLxkViRI
+ pVKQTqepAL8vKTAYDCsWIBglyzoBCsgr0v2/MxgaGvKWEmzgef5oV1cXuSV8i27T4gsPg4WUCnl3z1VU
+ VBwhzNVZdHaVkewjc7hHbtWXjY2NfRij0biiNDU19dbU1NQTVjnJKgQXr7Uk60i2/GPw/i+onON+A4sK
+ 2qgR6fnDAAAAAElFTkSuQmCC
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
- YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAARbSURBVEhL3dRbTJtlGAfwL9MYDzGZxHjaEHczdcm2LGJi
- xgwXM2N2SmLGFqAMkBUSKlAQsLTdVulsgCoQBTrYWEsLtKxA6QnKGcopHAdlNDuwyiHgBXoBGEhAs8fn
- fVsKpRhPdz7JL9Cv8H/e48fsVcHBwc+yWKzXQkJCXidCQ0PfCAsLO0Cw2eyDRGxsrH9CQsKbBJfLDUhP
- Tw/g8/lviUSiQwKB4FV31N6VkZEhHRwcXOjp6fmxo6OD6urqcnZ2djq7u7sfE/j7Y5vNNt3W1jaNn6fx
- bx7hZ0qj0diysrJeomFisXgfj8dLSUpK8khNTdUtLS3B+vo6LC8vw8rKyt+ytrYGm5ubYDab7Zi5nzZI
- Tk7m9/X1gdVqhebmZqqsrAwWFxdhbm4OhoaGqOHhYRgZGfEyOjpKjY+Pg91uh/n5eVhdXQWtVjuES/YC
- bZCYmBiN04KamhoPhUIBs7Oz4HA4oLe314MMZLf+/n7awOl0wszMDCwsLEBpaWkrDScVExNzGgOfVFdX
- A6FUKulsSPjAwAC0t7d7wbX2gnvhgftGZ5afn/+DO55hwsPDA3FZ1rcaFBYWwtjYGB1xU1MTNDY2eiHP
- 9tLS0kIbWCyW34VC4Tl3PMNERES8gw9/wZ33NCDrjc+gvr7eh16vpxoaGsBgMIDRaKTIrMmMcnNzHXFx
- cS+64xmGnGkMnqurq4Py8nIwmUyg09WCQqVFGlCqtV4qKmu2VelApdFTam0DyG9VAjc9uzgwVutPfJB2
- 5zmyB/vx1DjI5ubk5NC1lJbqIVpqBY6s5S80e7kkNW9clFimP5O0OAiW0Kwgt/Zp3JRhPFogl8sBLw6I
- 5FYobnwIhSZfBYTxIeQbH3h+fkcYXL5FMvS95QF8zDeU0GXCy9ZKzj5ZS7JZmSVtUGC+D9/UOjyuEzoX
- iW4Ksok7U/D1lpopEFP3gF85AWKZ6ckpnv4CbYDvEHVBQQENtzS3g+CmDfIa7nuH7QzEoJ2B17QuV1Gm
- agKEVZOQVjTw04nLqndpA7x1eTKZDPCdAkZrN1y9PQjSOodX4FbY7kBKc4+GZlRMwJfKcfpddE5rz3sJ
- pudpg5SUFJ5UKqUbrDbYQKge9RmdJxDDiCuaSRBVT4Kgyk5HTYK3CNTjEHrNUkTDSXE4nDCJRALkLmTf
- aAQRruHW6IQYklVph6/UEzQog8CRpldsB+5EvuOKTZsnk2o/dMczTGRkZBBekA18iwL7igqyqu00iPxD
- msJXqo+7kHr7LvAQaXxe3PToyAXdM+54homKijqOM/g5NjETz78Zkm6OwRdu3D+RWLa3+OJBYIksN9zR
- rgoKCjrOiY+fP8PJg8+LhoAjH/VxmSghRrzE7cK6bvn16MWcj9zRrvLz8zsYyuYMBHOLNz6JUf72b5zh
- 31oPyaydPxlXqsLIA67k7Xrq5UPHDh85dT7i7ffPsQ8Hsi79UwEnPj37ytGzpzHLH22v/x617z/43xXD
- /AEKo8fRIoTurgAAAABJRU5ErkJggg==
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAReSURBVEhL3dRbTJtlGAfwL9MYDzGZxKhzQ9zN1CXbsgwT
+ M2a4mBmz0yZmbAHKAFkhoQIFAUvbbZXOhoNSokAHG21poS0rUHqCcoZySsthpYxmB4ZAA16gF4CBBDR7
+ fN+3ByjFeLrzSX6BfoX/8x4/aq+KjIx8nkajvREVFXUAo9Ppb0ZHRx/EGAzGISwpKSk0NTX1LYzFYoXl
+ 5OSEcTict/l8/mEul/u6N2rvys3NFdlstsWBgYEfe3p6iL6+vtne3t7Z/v7+Jxj6/YnVap3p6uqaQZ9n
+ 0N88Rp8JtVptzc/Pf4WECQSCfWw2OzM9Pd0vKytLu7y8DBsbG7CysgKrq6t/y/r6OmxtbYHJZHKizP2k
+ QUZGBmdoaAgsFgu0t7cT1dXVsLS0BAsLC2C324nR0VEYGxsLMD4+TjgcDnA6neB2u2FtbQ00Go0dLdlL
+ pEFaWloCmhY0NDT4yWQymJ+fB5fLBYODg354ILsNDw+TBrOzszA3NweLi4tQVVXVScJxJSYmnpVKpU9V
+ KhVgcrmczAaHj4yMQHd3dwC01gHQXvihfSMzKy0t/cEbT1ExMTHhaFk2fA3KyspgYmKCjLitrQ1aW1sD
+ 4Gd76ejoIA3MZvPvPB7vgjeeomJjY99FD39BO+9vgNcbPYPm5uYgOp2OaGlpAb1eDwaDgcCzxjMqKipy
+ JScnv+yNpyh8plHwQlNTE9TU1IDRaAStthFkCg2iBrlSE6C2rmFbvRYUah2h1LSA5E4dsHIKKsKTNKHY
+ B9l3X8B7sB+dGhfe3MLCQrKWoiodJIgswCzp+AvtAa6ITJuXheaZz4QdLozGM8nwrX0WbcooOlogkUgA
+ XRzgSyxQ0foIyozBxJjhEZQaHvp/fofpPb5FSpDvzQ/hY46+kiwTumyd+OzjtcSblVfZBWLTA/im0eV3
+ E9N6CLXTUIDdnYavfRqmQUDcB07dJAiKDU/PsHWXSAP0DlGKxWISbm7vBu5tKxS3PAgM2xmIgnYG3tB4
+ XEfyFJPAq5+C7PKRn05eVbxHGqBbV1xSUgLonQIGSz9cl9pA1OQKCPSF7Q4k1PdJaG7tJHwpd5DvEgo7
+ B06lGl8kDTIzM9kikYhssFJvBZ5yPGh0/kAUhl1TTwFfNQXceicZNQ724SodQL9hLifhuJhMZrRQKAR8
+ FwputQIfraFvdDwUkl/nhK+UkyQoF0MjzandDtwJf8cSGLdOpzd+6I2nqLi4uAh0QTbRWxQY1xSQr3KS
+ IPwP2bJgWUHuQZb0HrAR3PiioO3x0Uva57zxFBUfH38CzeDnpLQ8dP5NkH57Ar7wYv2JtOq9pVTYgMY3
+ 3/JGeyoiIuIEMyXFfY5ZDJ+X24EpGQ9yFavExgIk70K7af712OXCj7zRngoJCTlEZzBHIlkVm58kyn/7
+ N85x7mxE5TW6TydXKVDkQU/ydj3z6uHjR46euRj7zvsXGEfCaVf+qbCTn55/7dj5sygrFNle/z1q33/w
+ vyuK+gPr6MfMLY+vbQAAAABJRU5ErkJggg==
@@ -229,27 +229,27 @@
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
- YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAASSSURBVEhLpZVrTJtlFMe7ZRFngKCDBLMPjC2ATm7hlkCA
- Em6DwiKMhktHS2kBdeXWCgUCUiA6hlAIMCjXcfkwCwwoREDKBDbkIteyViGMjCi6odOYGPXDQvh7mO83
- XMLll/yT931yzv88zznPm5d1WKqrqy1KS0svKJXKs8zSyWlsbHwjPz9fIpPJRlNSUh4LhcIfuFyunsPh
- tIaFhb3JhB0PqVTukfOJ4kl2Ti4kaelISBQjOiYWERHvIzg4GL6+vhom9Hik8KJ900U8pCfxkfWRCPLU
- ZCQmCBDCCUeAv/9+Afj4+Fgz4UdnuTkvqFeRs/dtgxxzKjmmamUYLk+HKDYSru4eYLPZCAkJ4TLhR2ex
- MSf3e/UtrKnLoOsopgIf40GlBLVSHi47u9MJ2AgPD/+QCT8anGvXrJprP99SVxVgpFKGvpIkaIoSMFub
- iQJBKELZnnv+fmx4e7PjmZSj4UG9ramv/aepuR7hPq5Qt9RgqL0GV31ckBblhwmlBIKIYJyzsn+HSTk6
- ZeLQlkoJF515fFQXpOFufTkyY6/g67o8dJV8gOhw/3om9HhMVN7g36+4gbFyCQZKEtEi5aK/RIzR2lzU
- S2NHmbDj061IsOxViHZ7i8XoLRbhXlEiBm9J0FEgRjE/aIIJOxlfFApV3Qohekj7hdrzBPhUEIimQvFv
- 2pmZJMP4eNeKWr2m6+rS6cbGmvoMBm8m9fDcyY3vKpbz9lTpUagQX8FA000saL+CrkKJpdRUzPP5WIiJ
- wbJAgBWFAqMazeFn4+TiknI1KlavKMzYG7mZAsOsFtMjo1jKyMQ0l4u56GgsxsVhMTISi/R1L7m4QJ+Y
- iIHOzgbG4tV4eXmlOTg4oKqqClPaIWxv6DH+cBoPMjIwLxTi+fIyttrasBgQgNXAQMw3qDBbVga9nR2m
- k5KQq1a7M1YH8fDwMPX09PzL0dERuXI5hr8cwj3NAO4UKaATiTBP7fhjawt/AtCXlOCb0lL06XQYothV
- c3M8ungRquzs24zdQZycnOKpCOzt7RFHLdjd3cUaGXZnZWGFer7E42EhJARzTU0YnJxEu0aDnvh4LLFY
- +I60QWqPjHz1TaOd33Zzc4OtrS3iKXGf4YkJtNLuH1GBWW9vjJOJhlrRNjKCbioyHxHx0niTtE1q43Cm
- GLuD0AmanZ2dYW1tDfrBvCzAI/OK5GSs+PlhhAwGaRYdU1PopfWZmhr8TDFPpVL8uF/gzBlU8/kdjN1B
- qMB7tPu/raysEENXcGdnBxeor/zr1zFNa6OnT+FuXR166Ee0SoZrRkZ4PjeHZ/39+J3eF+nkUpWKw9j9
- P3Z2dm6WlpYbEXR0rVYLExMTvG1jg1a6hgunT+MhGS3sm5OekLZIv5KemZqiUyajDh6OszSDPIVCsWls
- bIx9vUvDb6Yi8+fPw0CGj0k/Meably6hRy6fZAPGTP6hOWVhYeFsZmaWRs+N52xsegqzsgb7ExL09zmc
- p9qwsG0a+MxnlZVyllL51i8Gg7HBYHjtv9STYDBY8l68cA3a27NnAa8zq+br6+vmGxsbRiwWi/UvDmGP
- 4JI3q5gAAAAASUVORK5CYII=
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAASTSURBVEhLpZVrTJtlFMe7ZXHOAEEHCWYfGFsAndzCLYEA
+ JdwGhUXYGi5db7SAunJrZQUCUiA6hqMQYFAoY1w+zHIbhQhImcCGXORa1iqEkRFFt+k0Jkb9sBD+Hub7
+ DZdw+SX/5H2fnPM/z3PO8+Zl7ZXq6mrbsrKy02q1+gSzdHgaGxvfKCgokCkUiuG0tLRHYrH4By6Xa+Jw
+ OM3R0dFvMmEHQy5X+uZ+onp8NTcPsoxMiJKliE9IRGzs+4iIiEBQUJCeCT0Yabz4oEwJD5kpAuR8JIEy
+ PRXJIiEiOTEIDQnZKYDAwEAHJnz/LDblh3ercre/bVBiRqPERK0CgzcyIUmMg5ePL9hsNiIjI7lM+P6Z
+ b8zN+153HSu6chjbSqjAx7hfKUOtnIdzHj50AjZiYmI+ZML3B+fiRfum2s83dFWFGKpU4G5pCvTFIkzX
+ ZqNQGIUott92SDAbAQFsPpOyP3yptzX1tf9om+oRE+gF3a0aDLTW4EKgJzIuBWNMLYMwNgIn7V3eYVL2
+ T7k06laljIv2fAGqCzNwp/4GshPP4+u6fHSUfoD4mJB6JvRgjFVeEdyruIKRGzL0lSbjlpyL3lIphmvz
+ UC9PHGbCDk6nSmTXo5Js9ZRI0VMiQXdxMvqvy9BWKEWJIHyMCTscXxSJNZ0qMbpIO4Va84X4VBgGbZH0
+ N8PUVIp5dLRjSadbMXZ0GI0jI9q7ZnMAk7p3bufxO4qVvG1N5iVUSM+jT3sNc4avYKxQYyE9HbMCAeYS
+ ErAoFGJJpcKwXr/32bh7eqZduJRoUhVlbQ9dS4N52oDJoWEsZGVjksvFTHw85pOSMB8Xh3n6uhc8PWFK
+ TkZfe3sDY/Fq/P39M1xdXVFVVYUJwwA210wYfTCJ+1lZmBWL8XxxERstLZgPDcVyWBhmGzSYLi+HydkZ
+ kykpyNPpfBir3fj6+lr5+fn95ebmhjylEoNfDqBb34fbxSoYJRLMUjv+2NjAnwBMpaX4pqwMd41GDFDs
+ so0NHp45A83VqzcZu924u7vzqQhcXFyQRC3Y2trCChl25uRgiXq+wONhLjISM1ot+sfH0arXo4vPxwKL
+ he9Ia6TWuLhX3zTa+U1vb284OTmBT4k7DI6NoZl2/5AKTAcEYJRM9NSKlqEhdFKR2djYl8brpE1SC4cz
+ wdjthk7Q5OHhAQcHB9AP5mUBHplXpKZiKTgYQ2TQT7Nom5hAD61P1dTgZ4p5Ipfjx50Cx46hWiBoY+x2
+ QwXeo93/bW9vjwS6gs+ePcNp6qvg8mVM0trw0SO4U1eHLvoRLZPhyvHjeD4zg6e9vfid3ufp5HKNhsPY
+ /T/Ozs7ednZ2a7F0dIPBAEtLS7zt6IhmuoZzR4/iARnN7ZiTHpM2SL+SnlpZoV2hoA7ujRM0g3yVSrVu
+ YWGBHb1Lw2+iIrOnTsFMho9IPzHm62fPokupHGcDFkz+njlia2vrYW1tnUHPjScdHbuKcnL6e0Ui0z0O
+ 54khOnqTBj71WWWlkqVWv/WL2WxhNptf+y/1MJjNdrwXL7zCt7ddWMDrzKrN6uqqzdra2nEWi8X6FwKD
+ j96TtRA1AAAAAElFTkSuQmCC
@@ -258,19 +258,19 @@
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAOCSURBVEhLYyAHhKWUuQcnFZhAudQF0dG5fHsOnvgRFF9U
ARWiLghKLE378PHzf5pZUF7ft+v37z9YLaivr2cKii9ODgkp5IQKkQ4mzF7x8sfPX/+DEooroUJgEBNT
zN3cPfvAxh37/4KCESpMOpg/f/7vb99/oFjgl1QqNXfp+gefv3z9X1DbuxYqTB5YsGLz/89fv8EtCEwo
- Ndq85fDn7z9+/p+7dOnXkLhCabBCcsHcZRv/f/z09X9gQlFVSGJJ4OlzV/58/vr9/4x5y/8FxBV7QpWR
- D2YvXv//3YfP/yNSyvfcuvvo/5v3n/5PnLHoX1hKRTRUCWVgxsK1/9+8+wgMjo3/Hz97/b9/wZrvQQlF
+ Ndq85fDn7z9+/p+7dOnXkLhCabBCcsHcZRv/f/z09X9gQlFVSGJJ4OlzV/58/vr9//S5y/4FxBV7QpWR
+ D2YvXv//3YfP/yNSyvfcuvvo/5v3n/5PmL7wX1hKRTRUCWVgxsK1/9+8+wgMjo3/Hz97/b9/wZrvQQlF
7lBp4oCwVSkvt0leDI9ZYR2vSYEvVJghILZCuHfmsv990xb+nzZ/9f/Gnlkvg+MKtKHSxAE+q5JMaf+e
r2rxa/9rpW79r5O+47+Afc0cA+8Sl7KmvqeNffP/hybk/k/MrXoeGFMsBtVGHBCwrpytGLn0v5h7x3Ue
08JAXvN8c3G3rkvGhcf+q9gv/ts2Y93/6vr6fycv3PwfklBUD9VGHOA2LQiTC13wX9C2eh2DfT0LVJiB
1yw/ybb+5n/Htsf/JX36PjhGVO7Ob13038KvcCZUCXFAxKXthpBT9ysGrXo2qBAYCDs1rXHpfP5fPn7+
b26LgjCF0Dn/Lasu/Ve1X/pXwqv3oqBd1RRQnEGV4wbi9hP/Cjo0bIZywYDXvChBN3Pnf8nQOR/4jAvN
QGLqcav+u3a9+K+ftRvoo0W/dDJ3/xd2aj4ClGIEyeMEIvZtb/l9+r9zmeR7cpnnGQvYVc9Xi1v9X8K9
- 6y6HSZEsVBnYAoOcvf9B6kBBKWRXvVwlduV/HuMCa6gS7IDXrCROyq/+n1zYwv9yIfP+y4c2/OO3q12O
+ 6y6HSZEsVBnYAoOcvf9B6kBBKWRXvVwlduV/HuMCa6gS7IDXrCROyq/+n1zYwv9yIfP+y4fW/+O3q12O
7n3VmOX/xX0mnIdyGTiM8+QUIxb/57UoboIK4Qa8JvnqPKYFGbzmhYkclsXyUGEUoBy5+L+AQ808KBcM
hPyn/xC0q9sA5VIG5IPn/BaybVwG5QJBPZO037TfAra1q6EClAFR9+5rEt79zxlCQ5lBfF6TXCvZ4Ln/
uc2LisAKKAU85oWpChFL/gtYVa0HBSWfa8tTUfv+n9zmeeJQJZSCeiZg2t8sF7bov3zEsv8S9pP/cluU
- REElqQYYuUwLPbjN8nJ4TYvUoGJYAAMDAAhHadcjAT7sAAAAAElFTkSuQmCC
+ REElqQYYuUwLPbjN8nJ4TYvUoGJYAAMDAOHZadC3SBfkAAAAAElFTkSuQmCC
@@ -332,30 +332,30 @@
KCesl1WKXKMqE7KSEypEEtDM2X/Xtevlf5eu5/8VYtaXQYWpA7RCV7FJFmz65dj25L9t453/8tHrIqFS
1AEKUevDLaqv/rdruvffuOTsf9m4dcpQKcoBMAUJaGTueWldd/M/CGuk77wDlaIcqEVuElFL2n7erOLS
f/OqK/+Nis/8l49aHwWVJh+o5G5jl4tbn6KRtueDcenZ/yZl5/+DaJWkrUdJKr5BQCFqjbx83AZHYNIL
- UoheV6qctGWrevKOb3p5R/8bFp0EY4PCE/+Vkzbfl4pdJwzVRhwAVioO6qlz/mll7v+vnXXgv07O4f+6
+ UoheV6qctGWrevKOb3p5R/8bFp0EY4PCE/+Vkzbfl4pdJwzVRhwAVioO6qmz/2ll7v+vnXXgv07O4f+6
eUdQsHb2gf9KiZuOg4ILqo14AMxcfSDDsWGNtN3/VRK2vlOIW5vOUF/PBNVCGgAGi6V8/PzfqknbQOEL
- NHD6P8WELU+A1epShegNfqA6BKqUfKCSuFIUWMbrKMVukqOKgdQFDAwAp3n7vchE+HAAAAAASUVORK5C
+ NHDaP8WELU+A1epShegNfqA6BKqUfKCSuFIUWMbrKMVukqOKgdQFDAwApMP7ux+8q3QAAAAASUVORK5C
YII=
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
- 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
+ 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
@@ -431,24 +431,24 @@
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
- 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
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAP0SURBVEhL7VdLbBNXFE3aHQsqFl2jCiR2ZQMLJChVi1AU
+ POM3gQQKC7eVUMNPIFTh+WYSsCNhFgEJiQ2wScpPQhRnPrYBtUhAKf+Aq25oSfgsCBIQ7JDgBB7vkDcw
+ Y08Al1RCgiNdyR7fd8971/fde6bmPQetjSrd84jqJBt097KkuPciaroUbe4cIZsyA0TP9kRVZ3tU6/4a
+ vmNr3gGNjYc+jarW96Lu9jaauUdrEj0lbX8vTfzaT7fa92nKuU+TR/updqCPrm2/OtrEfIhq32Eb/NE0
+ zU94mOpANGeahNOZvxUROOU8pNvcN5tx4CZd3n6yQPTMX4Kcmc7DvYSoWib/WAlBs78hG93BDan86Db3
+ QSjB6wybjO05/bT+Z6sgatYCHrZGMtyEqNqUfw1CkK06yThcVPf3BYIhtfHO6zSWOlOQWnLFaHPXCNHd
+ Yant+EAs9UdB/eUGIwxu0jh4ky7U3cc4CEgl80QxlFjQjn6BXSK1/gDx7eeegUxS3bOC3B1DCiNmelJj
+ /NhnguJ8STR7JWnJ5hdvzA2Wb1hn5NH1R4ZA2p6+RyuIUQzEyOZje/8e8RYhZT91XBwS1MytiObM5a7j
+ AicTDbd/VcelIT+5wrIBUnyuICaa9d0yVpX+/xSkxHDP42Tc7Y2oM53JxMjk1yavlrw4fisjprXs/7qt
+ +9IU33HuGU5aDamHOsX5nN2KR/HOfwKksABxRHZmL2Gn9a4M7qdkHiuiaXCXquAVkpfecYlFxdqMB36T
+ 9Oyf/Oeq8DrSCuKJAppD+QHCjLt/xIeAsAIoN0GxW7n7xAGBw0ofV2KssTtJ7loVCOvtFQdQ7S3853Di
+ dyWNKM58NCE0I8RDc8IkY1yzuEs4Mdod2h7aH3d7a6DNSkyJyF3/voyHqcXi9QWkURgxbB1r9Gj41fTr
+ RbI1RTKyF1bsPDvsxcGcxgASFKuJu43BI0Z6McK8BTCMOIw6jDzuPi6Y2viKbfQ2SP1SacPW/CiTQj0V
+ OgzEIG1qOz5INHdYLxMCEAYY8hj2TMw1L4p3z0QWIAaYEJwhyvYPUkv2wuLW3KDcFZxIWEs2uQP1mjWV
+ 070CiEGKQsLJIFcg2vwBkC7IG8icJvPEQ8ieiJYu1bdaBTyDLPIKyTN1Xy+Fohk3WyD2Vy+ryG+xILb7
+ 1FN/yt7eHtD1LL1R/XAR6edhKxHWHKCrRN25tjz5ewG6KZwgaNikuu8GXZqwClAu0HA8XHV4ocOYOIc6
+ gaCP7eoZwbWAiIfqhCWO3H1BtnrLlVJ9m1VoaMlcFzVnxX8W9EHQWog9UbM7GvTcZRQLXl/mr3aeiEam
+ H6817I5ujsjpORPyCvP/oabmOYR3W8Rj8GnZAAAAAElFTkSuQmCC
diff --git a/Essay_Analysis_Tool/Notepad-Sharp.csproj b/Essay_Analysis_Tool/Notepad-Sharp.csproj
index a62fa62..b75d559 100644
--- a/Essay_Analysis_Tool/Notepad-Sharp.csproj
+++ b/Essay_Analysis_Tool/Notepad-Sharp.csproj
@@ -55,6 +55,12 @@
+
+ Form
+
+
+ DiffViewerForm.cs
+
Form
@@ -70,6 +76,9 @@
+
+ DiffViewerForm.cs
+
LoggerForm.cs
diff --git a/Essay_Analysis_Tool/changes.xml b/Essay_Analysis_Tool/changes.xml
index 6847fef..f78eefb 100644
--- a/Essay_Analysis_Tool/changes.xml
+++ b/Essay_Analysis_Tool/changes.xml
@@ -3,6 +3,7 @@
+ Implement diffmerge feature.
Changing language causes CurrentTB changed flag to be set to true.
Editor does not recognize .vbs extension.
App crashes when clicking File/Open submenu after fresh start.